创建型设计模式

知识补充

java反射机制

此处仅作最简单的应用型描述,因为下面会用到,所以在此补充,读者如果想深入了解java反射机制,请自行查资料。

举个简单例子:

Class c = Class.forName("String");
Object obj = c.newInstance();
return obj;

上面的代码能够返回一个String 对象(与new String()是一样的),比较神奇的是,我的String是出现在字符串中的。

所以你可以简单的理解成,java反射机制的一个最简单的应用就是从字符串到一个类的转变,即给你一个"String",你能通过反射机制获取String对象。

索引

  • 简单工厂模式
  • 工厂方法模式
  • 抽象工厂模式
  • 单例模式
  • 原型模式
  • 建造者模式

1. 简单工厂模式

简述

  • 简单工厂模式不是GOF提出的23种模式中的一个,简单工厂仅仅是一个小弟,他大哥叫抽象工厂模式。
  • 思路很简单,一张图就能搞明白:Java设计模式-内功修炼-创建型设计模式

理解

  • 上图一共四个类,抽象产品类,具体产品A类,具体产品B类,工厂类,前三个类的作用不用多说了,提取出一个抽象类有利于开闭原则以及代码复用。工厂类的作用:看上图左边的代码,根据传的参数来判断返回哪一个具体产品类。
  • 上图仅仅是一个基本原理图,聪明的读者一定发现,这种代码还是不符合开闭原则。

个人体会:

  • 其实也是针对接口编程的一种体现,Factory类中的factoryMethod(String arg):Product表示返回类型是Product即抽象类,根据参数判断返回哪个具体类。
  • 上述方法的缺点:仅仅将复杂的逻辑移动到了工厂类而已,并不能削减复杂度,而且如果新增产品的话,还是需要修改代码,导致扩展困难。
    适用范围:
  • 适用于创建的对象比较少,而且比较固定,不会产生扩展的情况。

2. 工厂方法模式

简述

上面说到,简单工厂方法对扩展很不友好,需要修改代码,不符合开闭原则,所以引入了工厂方法模式。
Java设计模式-内功修炼-创建型设计模式

理解

上图仅仅是最基本的原理图,读者可能还会有一些疑惑:当需要扩充新产品ConcreteProductB的时候怎么办?答案是:新建一个与之对应的ConcreteFactoryB,那么问题又来了:

每个产品都对应一个工厂,而且工厂里的factoryMethod()方法就执行了一行new语句,那要工厂有啥用呢?

  • 事情没有想象中的那么简单,其实引入工厂的初衷是因为类或者对象需要大量初始化代码,我们将默认初始化代码全部放入factoryMethod中,这样对于客户端代码来说就友好了很多,即用工厂方法创建的对象是具有一定默认初始化的。

这种方法能做到开闭原则的对修改关闭,对扩展开放吗?
能,解析如下:当需要新增ConcreteProductB的时候,新建ConcreteProductB和ConcreteFactoryB,这就是对扩展开放,那么客户端在创建产品的时候还是要修改一些语句呀,比如需要将 ConcreteFactory.factoryMethod() 修改成 ConcreteFactoryB.factoryMethod() 那岂不是还不遵循开闭原则,莫急,下面解决这个问题。

如何解决上面的问题
用反射,关于反射看文首的知识补充。解决方案在上两篇文章中提到过,依赖注入,即将类名写在xml文件中,然后读取xml文件,利用反射获取相应对象,下面给一个示例代码:

public class XMLUtil {  
//该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象  
    public static Object getBean() {  
        try {  
            //创建DOM文档对象  
            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();  
            DocumentBuilder builder = dFactory.newDocumentBuilder();  
            Document doc;                             
            doc = builder.parse(new File("config.xml"));   

            //获取包含类名的文本节点  
            NodeList nl = doc.getElementsByTagName("className");  
            Node classNode=nl.item(0).getFirstChild();  
            String cName=classNode.getNodeValue();  

            //通过类名生成实例对象并将其返回  
            Class c=Class.forName(cName);  
            Object obj=c.newInstance();  
            return obj;  
        }     
        catch(Exception e) {  
            e.printStackTrace();  
            return null;  
         }  
    }  
}
class Client{
	public static void main(String args[]){
		LoggerFactory factory;
		Logger logger;
		factory = (LoggerFactory)XMLUtil.getBean();
		logger = factory.createLogger();
		logger.writeLog();
	}
}

再次引入一个问题:
客户得修改配置文件岂不是很麻烦,其实简介方案很简单,将修改配置文件部分做成图形界面就ok了。

总结

优点:

  • 用户无需关心创建产品的细节
  • 在系统中加入新产品的时候,无需修改代码,只需去修改配置文件。然后加入具体产品类和其对应的工厂方法。

缺点也很明显:

  • 另外增加了类的个数,每次引入新产品都需要加具体产品类和对应的工厂方法。
  • 引入抽象层,增加了理解难度,而且还用到了反射,增加了系统实现难度。

适用场景:

  • 客户端不知道它所需要的对象的类,只需要知道对应的工厂即可。
  • 在程序运行时确定使用哪个子类,然后进行替换,覆盖,使系统更容易扩展。

3. 抽象工厂模式

简述

抽象工厂模式又称为Kit模式,可以理解成是一种打包式的工厂模式,即工厂模式如果子工厂类无限扩充怎么办?那把他们打包一下,再增加一个抽象层,也就是抽象工厂。
Java设计模式-内功修炼-创建型设计模式

理解

如果能够理解工厂方法模式的话,再理解抽象工厂方法模式就不难了,他们本质上是相同的,抽象工厂针对的是一个产品家族,而工厂方法针对的是一个产品。

总结

优点

隔离了具体类的生成,生成了产品族,而且增加新的产品族很方便

缺点

增加新的产品结构很难

适用场景

  • 系统中有产品族需要组合。
  • 产品族中的产品是有约束的,即这些产品族是一起生效的,比如一个皮肤中的背景+按钮样式他们是一起生效的,属于同一款主题中的不同控件。
  • 产品结构稳定,不会频繁更新产品结构。

4.单例模式

相关文章: