工做中要开发一个小的功能,我并没用立刻去实现,而是想了想看看能不能作的更有扩展性一些。固然思考的结果有多是过分的设计了。java
如今把功能要求简单描述一下,而后在说实现方法:node
系统接受到一个XML格式的消息体,而后须要根据一些需求把XML消息作一些过滤,修改,而后存储起来。spring
实现的大概思路就是用过滤器的思想再加上逻辑插件化。apache
下面就是代码骨架: dom
public interface XMLAdapter { public boolean update(XMLDocument targetDocument); }
上面的接口是咱们的逻辑要实现。XMLDocument 是XML用dom4j解析以后的类。相似于一个java bean。ide
import org.apache.log4j.Logger; public class ExampleAdapter implements XMLAdapter { private String nodesValue; private String nodeValue; private static Logger logger = Logger.getLogger(ExampleAdapter.class); @Override public boolean update(XMLDocument targetDocument) { //our logic is implemented here } public String getNodesValue() { return nodesValue; } public void setNodesValue(String nodesValue) { this.nodesValue = nodesValue; } public String getNodeValue() { return nodeValue; } public void setNodeValue(String nodeValue) { this.nodeValue = nodeValue; } }
这是一个实现类。对XML的操做:过滤节点,删除节点,修改节点的工做都在update方法里面实现。这个类有两个成员。update方法里面用这两个成员来作一些逻辑。这里咱们用注入的方式来给这两个成员赋值。
下面是注入的一个简单实现:this
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="exampleAdapter" class="com.example.ExampleAdapter"> <property name="nodesValue"> <value>XXX</value> </property> <property name="nodeValue"> <value>YYY</value> </property> </bean> </beans>
对spring熟悉的人看到这个XML配置文件应该很熟悉了。下面是这个XML文件对应的工厂类。
import java.io.FileInputStream; import java.io.InputStream; import java.lang.reflect.Method; import java.util.concurrent.ConcurrentHashMap; import java.util.Iterator; import java.util.Map; import org.apache.log4j.Logger; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.dom4j.Attribute;
public class AdapterFactory { private Map<String, Object> adapterMap = new ConcurrentHashMap<String, Object>(); private static Logger logger = Logger.getLogger(AdapterFactory.class); /** * init AdapterFactory. parse adapter.xml to bean map. * @param filePath Adaptor configuration file path. */ public void init(String filePath) { if (filePath == null || filePath.length() == 0) { logger.warn("empty configuration file path and name!"); return; } try { SAXReader reader = new SAXReader(); InputStream ins = new FileInputStream(filePath); Document doc = reader.read(ins); Element root = doc.getRootElement(); Element attributeElement; for (Iterator i = root.elementIterator("bean"); i.hasNext();) { attributeElement = (Element) i.next(); Attribute id = attributeElement.attribute("id"); Attribute cls = attributeElement.attribute("class"); Class adaptor = Class.forName(cls.getText()); java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(adaptor); java.beans.PropertyDescriptor[] pd = info.getPropertyDescriptors(); Method mSet = null; Object obj = adaptor.newInstance(); for (Iterator ite = attributeElement.elementIterator("property"); ite.hasNext();) { Element propertyElement = (Element) ite.next(); Attribute name = propertyElement.attribute("name"); String value = null; for (Iterator ite1 = propertyElement.elementIterator("value"); ite1.hasNext();) { Element node = (Element) ite1.next(); value = node.getText(); break; } for (int k = 0; k < pd.length; k++) { if (pd[k].getName().equalsIgnoreCase(name.getText())) { mSet = pd[k].getWriteMethod(); mSet.invoke(obj, value); } } } adapterMap.put(id.getText(), obj); } } catch (Exception e) { logger.warn("init AdaptorFactory failed", e); } } public Map<String, Object> getAdapterMap() { return adapterMap; } }
这个类说白了就是经过反射把XML文件配置的类load到一个Map中。
能够参考下面这篇blog对这个类的说明spa
http://blog.csdn.net/wwww1988600/article/details/7286887.net
这样经过AdapterFactory咱们就能够拿到全部的咱们配置的类。下面就是在咱们的主逻辑中把咱们XML配置的这些类调起来。这里有一个想法:当咱们有新需求时,在XML配置文件添加一些实现类时,咱们的主逻辑代码可不能够不修改?插件
因此就引入下面这个类:
import java.util.Map; import org.apache.log4j.Logger;
public class ExampleFilterChain { private static Logger logger = Logger.getLogger(ExampleFilterChain.class); private static AdapterFactory adapterFactory; private static ExampleFilterChain filterChain ; private ExampleFilterChain(String filePath) { init(filePath); } public static synchronized ExampleFilterChain getInstance(String filePath) { if(filterChain == null) { filterChain = new ExampleFilterChain(filePath); } return filterChain; } /** * * @param filePath AdapterFactory configuration files */ private void init(String filePath) { adapterFactory = new AdapterFactory(); adapterFactory.init(filePath); } /** * this method will issue all adapter instances which defined in adapter.xml */ public void filter(XMLDocument targetDocument){ Map<String,Object> maps = adapterFactory.getAdapterMap(); if(maps == null || maps.size() == 0){ logger.info("can not find any adapter instances"); return; } Object[] keys = maps.keySet().toArray(); for(Object key : keys){ ((XMLAdapter)maps.get(key)).update(target); } } }
这个类的做用就是初始化咱们的AdaperFactory。他有一个public方法:filter()。这个方法把咱们load进来的全部的实现类都执行一遍。这里留下一些问题:当一个实现类执行失败后,后面的实现类要不要继续执行,等等吧。之后在考虑。
下面的工做就简单了,在主逻辑里面调用这个ExampleFilterChain的filter方法就能够了。
private ExampleFilterChain chain = ExampleFilterChain.getInstance(adapter.xml"); ..... chain.filter(xmlDocument); .....
OK。结束。
这种实现的一个好处是:当咱们有新的需求时,只要实现XMLAdaper接口,并把实现类配置到adapter.xml中就能够了。实现者不须要去修改主逻辑和其余代码。