#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 Testingparticipant Directorparticipant ConstructBuilderTesting -> ConstructBuilder: newTesting -> Director : constructDirector -> ConstructBuilder : initConstructBuilder -->> 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 staticT 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: int_java_se@163.com * @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 []