为什么80%的码农都做不了架构师?>>>
#Java Builder模式-组装复杂的实例。
- 上一面介绍 初探Java Builder模式--组装复杂的实力 简单介绍了下我在项目中的使用。
Builder
-
什么是Builder模式?
-
大都市中林立着许多高楼大厦,这些高楼大厦都是具有建筑结构的大型建筑。通常,建造和构建这种具有建筑结构的大型物体在英文中成为Build。
在建筑大楼时,需要打牢地基,搭建框架,然后自下而上地一层一层盖起来。通常,在建造这种具有复杂结构的物体时,很难一气呵成。我们需要首先建造组成这个物体的各个部分,然后分段将他们组装起来。
---图解设计模式
-
-
这个用例并不是特别的明显,大体的思路是这样的。
-
改造上次的代码。首先分析下上篇文章中ztree的数据结构
- 依赖库
- commons-lang3
- 3.4
- com.thoughtworks.xstream
- 1.4.10
- com.fasterxml.jackson.core
- 2.8.1
- commons-lang3
Builder中角色
关系大概就是这样的样子
- 建造者 Builder
- 具体建造者ConcreteBuilder
- ZtreeJSONBuilder
- ZtreeXMLBuilder
- 监工 Director
- 测试 Testing
participant Testing
participant Director
participant ConstructBuilder
Testing -> ConstructBuilder: new
Testing -> Director : construct
Director -> ConstructBuilder : init
ConstructBuilder -->> Director :
Director-->> Testing: successful
Builder建造者
package cn.z201.gof.builder;
import java.util.Collection;
public abstract class ZtreeBuilder {
public static final String TOP = "0001";
public abstract String treeName();
public abstract Object findResuls();
public abstract void id(String id);
public abstract void pid(String pid);
public abstract void name(String name);
public abstract void url(String url);
public abstract void open(boolean open);
public abstract void parent(boolean parent);
public abstract void children(Collection children);
public abstract String id();
public abstract String pid();
public abstract String name();
public abstract String url();
public abstract boolean open();
public abstract boolean parent();
public abstract Collection children();
}
ConcreteBuilder具体的建造者
package cn.z201.gof.builder;
import java.util.ArrayList;
import java.util.Collection;
import cn.z201.gof.utils.JsonUtil;
public class ZtreeJSONBuilder extends ZtreeBuilder{
//本级Id
private String id;
//父级菜单的 id
private String pid;
//中文名称
private String name;
//点击地址
private String url;
//是否展开
private boolean open;
//是否为父节点
private boolean isParent;
private Collection children = new ArrayList();;
public ZtreeJSONBuilder() {
}
@Override
public String treeName() {
return this.getClass().getSimpleName();
}
@Override
public Object findResuls(){
return JsonUtil.toJson(this);
}
@Override
public void id(String id) {
this.id = id;
}
@Override
public void pid(String pid) {
this.pid = pid;
}
@Override
public void name(String name) {
this.name = name;
}
@Override
public void url(String url) {
this.url = url;
}
@Override
public void open(boolean open) {
this.open = open;
}
@Override
public void parent(boolean isParent) {
this.isParent = isParent;
}
@Override
public void children(Collection children) {
this.children = (Collection) children;
}
@Override
public String id() {
return this.id;
}
@Override
public String pid() {
return this.pid;
}
@Override
public String name() {
return this.name;
}
@Override
public String url() {
return this.url;
}
@Override
public boolean open() {
return this.open;
}
@Override
public boolean parent() {
return this.isParent;
}
@Override
public Collection children() {
return this.children;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPid() {
return pid;
}
public void setPid(String pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public boolean isOpen() {
return open;
}
public void setOpen(boolean open) {
this.open = open;
}
public boolean getIsParent() {
return isParent;
}
public void setIsParent(boolean isParent) {
this.isParent = isParent;
}
public Collection getChildren() {
return children;
}
public void setChildren(Collection children) {
this.children = children;
}
}
package cn.z201.gof.builder;
import java.util.ArrayList;
import java.util.Collection;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import cn.z201.gof.utils.XMLUtil;
@XStreamAlias("ZtreeXMLBuilder")
public class ZtreeXMLBuilder extends ZtreeBuilder{
//本级Id
private String id;
//父级菜单的 id
private String pid;
//中文名称
private String name;
//点击地址
private String url;
//是否展开
private boolean open;
//是否为父节点
private boolean isParent;
private Collection children = new ArrayList();
public ZtreeXMLBuilder() {
}
@Override
public String treeName() {
return this.getClass().getSimpleName();
}
@Override
public Object findResuls(){
XStream xstream = new XStream();
xstream.autodetectAnnotations(true);
xstream.alias("ZtreeXMLBuilder", ZtreeXMLBuilder.class);
xstream.registerConverter(new XMLUtil());
return xstream.toXML(this);
}
@Override
public void id(String id) {
this.id = id;
}
@Override
public void pid(String pid) {
this.pid = pid;
}
@Override
public void name(String name) {
this.name = name;
}
@Override
public void url(String url) {
this.url = url;
}
@Override
public void open(boolean open) {
this.open = open;
}
@Override
public void parent(boolean isParent) {
this.isParent = isParent;
}
@Override
public void children(Collection children) {
this.children = (Collection) children;
}
@Override
public String id() {
return this.id;
}
@Override
public String pid() {
return this.pid;
}
@Override
public String name() {
return this.name;
}
@Override
public String url() {
return this.url;
}
@Override
public boolean open() {
return this.open;
}
@Override
public boolean parent() {
return this.isParent;
}
@Override
public Collection children() {
return this.children;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPid() {
return pid;
}
public void setPid(String pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public boolean getOpen() {
return open;
}
public void setOpen(boolean open) {
this.open = open;
}
public boolean getIsParent() {
return isParent;
}
public void setIsParent(boolean isParent) {
this.isParent = isParent;
}
public Collection getChildren() {
return children;
}
public void setChildren(Collection children) {
this.children = children;
}
}
Director监工
package cn.z201.gof.builder;
import cn.z201.gof.utils.CodingFactoryUtil;
public class Director{
private ZtreeBuilder> ztreeBuilder;
public > Director(ZtreeBuilder builder){
ztreeBuilder = builder;
}
public Object getResuls(){
return ztreeBuilder.findResuls();
}
public void construct(){
if(null == ztreeBuilder.id()){
ztreeBuilder.id(ZtreeBuilder.TOP);
}
if(null == ztreeBuilder.name()){
ztreeBuilder.name(ztreeBuilder.treeName());
}
if(null == ztreeBuilder.pid()){
ztreeBuilder.pid(CodingFactoryUtil.ztreeCodingFactory(ZtreeBuilder.TOP, ZtreeBuilder.TOP));
}else{
ztreeBuilder.pid(CodingFactoryUtil.ztreeCodingFactory(ztreeBuilder.pid(), ztreeBuilder.id()));
}
}
}
工具类
package cn.z201.gof.utils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
public class CodingFactoryUtil {
private static final Logger LOGGER = Logger.getLogger(CodingFactoryUtil.class);
/** ztree的编码加工规则 */
public static final int ztreeRules = 4;
/** 补码 */
public static final String complement = "0";
/**
* @param head 前置编码 比如0001
* @param tail 后置编码 比如1
* @param reules 编码长度 比如4 表示长度四位
* @return 00010001
* @throws Exception
*/
public static String codingFactory(String head ,String tail ,int reules) throws Exception{
if(tail.length() > reules) throw new Exception();
for (int i = 0; i < reules; i++) {
if(tail.length() == reules) break;
tail = StringUtils.join(complement , tail);
}
return StringUtils.join(head , tail);
}
public static String ztreeCodingFactory(String head , String tail){
try {
return codingFactory(head , tail , ztreeRules);
} catch (Exception e) {
LOGGER.error(e.getMessage());
}
return null;
}
}
package cn.z201.gof.utils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
/**
* JSON 和 Java对象相互转换
*/
public class JsonUtil {
private static final ObjectMapper objectMapper;
static {
objectMapper = new ObjectMapper();
//去掉默认的时间戳格式
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//设置为中国上海时区
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
objectMapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
//空值不序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
//反序列化时,属性不存在的兼容处理
objectMapper.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//序列化时,日期的统一格式
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//单引号处理
objectMapper.configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
objectMapper.configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
//objectMapper.configure(com.fasterxml.jackson.core.JsonParser.Feature.CANONICALIZE_FIELD_NAMES, true);
}
public static T toObject(String json, Class clazz) {
try {
return objectMapper.readValue(json, clazz);
} catch (JsonParseException e) {
throw new MepException(e);
} catch (JsonMappingException e) {
throw new MepException(e);
} catch (IOException e) {
throw new MepException(e);
}
}
public static T toCollection(String json, TypeReference typeReference) {
try {
return objectMapper.readValue(json, typeReference);
} catch (JsonParseException e) {
throw new MepException(e);
} catch (JsonMappingException e) {
throw new MepException(e);
} catch (IOException e) {
throw new MepException(e);
}
}
public static String toJson(T entity) {
try {
return objectMapper.writeValueAsString(entity);
} catch (JsonGenerationException e) {
throw new MepException(e);
} catch (JsonMappingException e) {
throw new MepException(e);
} catch (IOException e) {
throw new MepException(e);
}
}
}
/**
* Copyright © 2017 z201.cn . All rights reserved.
* @Title: XMLUtil.java
* @Prject: learn-gof
* @Package: cn.z201.gof.utils
* @author: [email protected]
* @date: 2017年7月15日 上午3:51:36
*/
package cn.z201.gof.utils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
public class XMLUtil implements Converter{
@SuppressWarnings("rawtypes")
private Class currentType;
private final String clazzNames[] = {"ZtreeXMLBuilder"};// 定义所要转换的对象及所包含的对象名称
private List clazzNamesList;
@SuppressWarnings("rawtypes")
@Override
public boolean canConvert(Class type) {
currentType = type;
clazzNamesList = Arrays.asList(clazzNames);
if (clazzNamesList.contains(currentType.getSimpleName())) {
return true;
} else {
return false;
}
}
@Override
public void marshal(Object source, HierarchicalStreamWriter writer,
MarshallingContext context) {
try {
marshalSuper(source, writer, context, currentType);
} catch (Exception e) {
e.printStackTrace();
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private Object getObj(Class clazz, String nodeName, Object source)
throws Exception {
Method method = clazz.getMethod("get"
+ Character
.toUpperCase(nodeName.substring(0, 1).toCharArray()[0])
+ nodeName.substring(1));
Object obj = null;
obj = method.invoke(clazz.cast(source), new Object[0]);
return obj;
}
@SuppressWarnings({ "rawtypes" })
private void objConverter(Object source, HierarchicalStreamWriter writer,
MarshallingContext context, Class clazz, String nodeName,
Class fieldClazz) throws Exception {
Object obj = getObj(clazz, nodeName, source);
writer.startNode(nodeName);
marshalSuper(obj, writer, context, fieldClazz);
writer.endNode();
}
@SuppressWarnings({ "rawtypes" })
private void collectionConverter(Object source,
HierarchicalStreamWriter writer, MarshallingContext context,
Class clazz, String nodeName, Field field) throws Exception {
Type types[] = ((ParameterizedType) field.getGenericType())
.getActualTypeArguments();
Object obj = getObj(clazz, nodeName, source);
Collection collection = null;
if (field.getType().equals(List.class)) {
collection = (List) obj;
} else if (field.getType().equals(Set.class)) {
collection = (Set) obj;
}
writer.startNode(nodeName);
for (Object object : collection) {
String clazzName = ((Class) types[0]).getSimpleName();
writer.startNode(Character.toLowerCase(clazzName.substring(0, 1)
.toCharArray()[0]) + clazzName.substring(1));
marshalSuper(object, writer, context, (Class) types[0]);
writer.endNode();
}
writer.endNode();
}
@SuppressWarnings({ "rawtypes" })
private void basicTypeConverter(Object source,
HierarchicalStreamWriter writer, MarshallingContext context,
Class clazz, String nodeName) throws Exception {
Object obj = getObj(clazz, nodeName, source);
writer.startNode(nodeName);
writer.setValue(obj == null ? "" : obj.toString());
writer.endNode();
}
@SuppressWarnings({ "rawtypes" })
private void marshalSuper(Object source, HierarchicalStreamWriter writer,
MarshallingContext context, Class clazz) throws Exception {
Field fields[] = clazz.getDeclaredFields();
for (Field field : fields) {
String nodeName = field.getName();
Class fieldClazz = field.getType();
if (clazzNamesList.contains(fieldClazz.getSimpleName())) {
objConverter(source, writer, context, clazz, nodeName,
fieldClazz);
} else if (Arrays.asList(fieldClazz.getInterfaces()).contains(
Collection.class)) {
collectionConverter(source, writer, context, clazz, nodeName,
field);
} else {
basicTypeConverter(source, writer, context, clazz, nodeName);
}
}
}
@Override
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
return null;
}
}
测试
package cn.z201.gof;
import org.junit.Test;
import cn.z201.gof.builder.Director;
import cn.z201.gof.builder.ZtreeBuilderXML;
import cn.z201.gof.builder.ZtreeBuilderJSON;
public class Testing {
@Test
public void test(){
Director director = new Director(new ZtreeJSONBuilder());
director.construct();
System.out.println(director.getResuls());
director = new Director(new ZtreeXMLBuilder());
director.construct();
System.out.println(director.getResuls());
}
}
测试结果
- 这里做了区分,所以使用了两种数据形式展示。
{"id":"0001","pid":"00010001","name":"ZtreeJSONBuilder","url":null,"open":false,"isParent":false,"children":[]}
0001
00010001
ZtreeXMLBuilder
false
false
[]