工做中要開發一個小的功能,我並沒用立刻去實現,而是想了想看看能不能作的更有擴展性一些。固然思考的結果有多是過分的設計了。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中就能夠了。實現者不須要去修改主邏輯和其餘代碼。