一、简单工厂,违背了(OCP).
public class TVFactory { public static final String Hai_Er="海尔"; public static final String CHANG_HONG="长虹"; publicstatic TV createTV(String type){ TVtv=null; if(Hai_Er.equals(type)){ tv=newHaiErTV(); }elseif(CHANG_HONG.equals(type)){ tv=newChangHongTV(); }else{ throw new RuntimeException("无法产生!"); } returntv; } } public interface TV { public void turnOn();//打开电视 public void turnOff();//关闭电视 } public class HaiErTV implements TV { @Override publicvoid turnOn() { //TODO Auto-generated method stub System.out.println("HaiErTV.turnOn()"); } @Override publicvoid turnOff() { //TODO Auto-generated method stub System.out.println("HaiErTV.turnOff()"); } } public class ChangHongTV implements TV { @Override publicvoid turnOn() { System.out.println("ChangHongTV.turnOn()"); } @Override publicvoid turnOff() { System.out.println("ChangHongTV.turnOff()"); } } public class Client { /** * 函数功能说明 * huxj 2014-10-1 * @参数: @param args * @return void * @throws */ publicstatic void main(String[] args) { TV tv=TVFactory.createTV("海尔"); tv.turnOn(); tv.turnOff(); } }
运行结果:
简单工厂的弊端运:
现在我们需要“海信”品牌的电视的,操作如下:
1)添加一个“海信电视”类继承“电视”抽象类。
2)修改“TVFactory ”类,添加有关“海信电视”的逻辑处理。
3)客户端“Client”类中,品牌改变,代码跟着改变。
总结:简单工厂2)3)说明步骤严重违背了设计模式的基本原则“The Open-Closeed-Principle, 开放封闭”原则。
简单工厂严重违背了“开放封闭”原则,那是不是简单工厂就没有用武之地了呢?
其实不是这样的,当我们需求稳定的时候,比如我们就只需要“长虹”“海尔”两种品牌的电视机,那么我们就不需要修改“TVFactory”,这时候用简单工厂与后续要将的其他用工厂要简单很多。很多东西放到合适的地方才能发挥它自己独特的魅力。
下面,就上面两个问题,们就逐步引入工厂方法,反射来一一解决问题。
二、工厂方法:解决"需求改变,修改工厂"的问题
public interface TVFactory{ publicTV createTV(); } publicclass TVFactoryHaiEr implements TVFactory { /** * */ @Override publicTV createTV() { returnnew HaiErTV(); } } publicclass TVFactoryChangHong implements TVFactory { /** * */ @Override publicTV createTV() { returnnew ChangHongTV(); } } publicclass Client { /** * 函数功能说明 * huxj 2014-10-1 * @参数: @param args * @return void * @throws */ publicstatic void main(String[] args) { TVFactorynewFactory=new TVFactoryHaiEr(); //TVFactorynewFactory=new TVFactoryChangHong(); newFactory.createTV().turnOn(); newFactory.createTV().turnOff(); } }
大家看UML图和代码之后应该比较容易理解:
1)解决的办法就是由父类派生出对应的多个共产(每个工厂对应该品牌的产品)这就将职责分离,符合了“单一职责”的原则。
这时,当我们需要“海信”品牌的电视的时候,只需要添加“海信电视”类,及对应的工厂即可,这样最做了添加(品牌删除同样也是),也就是说不必类内部代码,这样就遵循“OCP”原则!
2)但是要想解决客户端的问题,请看下文讲解:
三、工厂方法+反射,解决客户端违背“OCP”原则
public static voidmain(String[] args) { TVFactorynewFactory=new TVFactoryHaiEr(); //TVFactorynewFactory=new TVFactoryChangHong(); newFactory.createTV().turnOn(); newFactory.createTV().turnOff(); } }
关于TV所有的代码,目前只有客户端这里有变化,而且变化的地方
TVFactorynewFactory=new TVFactoryHaiEr()即实例化的工厂,其实解决此问题的思路很简单,把实例化工厂以变量的思维进行解决,通过配置文给变量赋值即可,下面就此思路展开:
配置工厂
sys-config.xml <?xmlversion="1.0" encoding="UTF-8"?> <config> <dao-factory> <item-dao-factory>test.TVFactoryHaiEr</item-dao-factory> </dao-factory> </config>
读取配置文件,返回所需的工厂类
/** * 采用单例模式解析sys-config.xml文件 * @author Administrator * */ public classXmlConfigReader { //懒汉式(延迟加载lazy) privatestatic XmlConfigReader instance = null; //key表示<dao-factory>标签名 //value标签中的值,具体完整路径(成员变量) privateMap<String,String> daoFactoryMap=new HashMap<String,String>(); privateXmlConfigReader() { SAXReaderreader = new SAXReader(); InputStreamin =Thread.currentThread().getContextClassLoader().getResourceAsStream("sys-config.xml"); try { Documentdoc = reader.read(in); //读取DaoFactory信息 ListdaoFactoryList=doc.selectNodes("/config/dao-factory/*"); //获得子节点标签值 for(inti=0;i<daoFactoryList.size();i++){ ElementdaoFactoryElt=(Element)daoFactoryList.get(i); StringtagName=daoFactoryElt.getName(); StringtagText=daoFactoryElt.getText(); //System.out.println(tagName); //System.out.println(daoFactoryElt.elementText("item-dao-factory")); //System.out.println("读取的内容是:"+tagText); //把取的值放入map当中 daoFactoryMap.put(tagName,tagText); } }catch (DocumentException e) { //TODO Auto-generated catch block e.printStackTrace(); } } publicstatic synchronized XmlConfigReader getInstance() { if(instance == null) { instance= new XmlConfigReader(); } returninstance; } /** * @param name * 返回工厂类的具体路径。 * *@return value值 * */ publicString getDaoFactory(String name){ returndaoFactoryMap.get(name); } }
客户端代码:
运行结果:/** * @类功能说明:工厂方法+反射 解决:工厂方法违背开闭原则的问题 * @作者:huxj * @创建时间:2014-10-1下午12:16:37 * @版本:V1.0 */ public class Client { /** * 函数功能说明 * huxj 2014-10-1 * @参数: @param args * @return void * @throws */ publicstatic void main(String[] args) { //通过配置文件获取,工厂类,解决修改代码的功能。 StringclassName=XmlConfigReader.getInstance().getDaoFactory("item-dao-factory"); //把类装载到内存里 TVFactoryfactory=null; try { factory= (TVFactory)Class.forName(className).newInstance(); }catch (InstantiationException e) { e.printStackTrace(); }catch (IllegalAccessException e) { e.printStackTrace(); }catch (ClassNotFoundException e) { e.printStackTrace(); } factory.createTV().turnOn(); factory.createTV().turnOff(); } }
通过变量获取StringclassName=XmlConfigReader.getInstance().getDaoFactory("item-dao-factory")工厂类,然后TVFactory factory = (TVFactory)Class.forName(className).newInstance()
实例化;从配置文件中获取变化的类,这样很好的维护了“OPC”原则,而且使更换数据库更加的灵活。
总结:
问题总算圆满解决,我感觉“perfect!”。静下心来,学习有很多的乐趣!