《大话设计模式》读书笔记:三种工厂模式

简单工厂模式:定义一个工厂类,工厂类中包含了必要的逻辑判断并根据客户端的选择条件动态实例化相关的类。简单工厂模式将类的实例化从客户端延迟到了工厂类中。

 

工厂方法模式:定义一个用于创建对象的接口(抽象工厂),让子类(工厂类)决定实例化哪一个类(产品类)。工厂方法模式是将简单工厂模式的逻辑判断从单个工厂类的内部移到了客户端中进行,通过实例化不同的工厂类来实例化不同的产品类(功能类)。工厂方法模式是将类的实例化从单一的工厂类拆分到了抽象工厂的多个子类。

 

抽象工厂模式:提供了一个创建一系列相关或者相互依赖对象的接口(抽象工厂),而无需指定它们具体的类。抽象工厂中包含创建不同产品类的抽象方法,由实现抽象工厂接口的具体工厂类在实现这些方法的时候,具体指定究竟要实例化哪种产品类,从而完成了逻辑判断与类实例化的分离。

 

三种工厂模式的图示参见《大话设计模式》P12、P71、P150。

 

从根本上说,工厂模式就是为了在大量关联类的实例化的时候解耦合用的。当客户端中的一个逻辑选择会产生多个不同的业务过程的时候,可以将这些业务过程封装成不同的类,再通过逻辑选择进行分支调用。

 

简单工厂模式就是将客户端中逻辑判断后分支调用不同业务类的过程剥离出来,形成一个新的工厂类,并析取出这些业务类的父类,让这个工厂类通过不同的逻辑选择实例化这个父类的不同子类,并返回给客户端。这样做的好处在于,剥离之后减少了客户端类的职责(单一职责原则),使其不再直接与具体的业务类产生联系;同时,形成工厂类之后,相关的业务类被组织到了一起,也便于管理。

 

但是,如果对于扩展频繁的模块,每次新扩展一个业务类,就要对工厂类添加一条新的逻辑选择,这样一来就大大违反了开放-封闭原则。于是就有了简单工厂模式的进化版——工厂方法模式。工厂方法模式把逻辑选择还给了客户端(因为无论如何客户端都是需要频繁修改的),同时将工厂类进行抽象。在工厂方法模式中,每个业务流程只对应一个实现自抽象工厂接口的具体工厂类,将这个具体工厂类实例化的产品类返回到客户端中完成业务流程。这样,就将工厂类的职责减少了(单一职责原则),因为每个具体的工厂类只负责实例化一个产品类。这样一来,对于工厂类和产品类而言,开放-封闭原则就能保证了。

 

然而,逻辑选择依然存在于代码中,它的存在就标志着只要一扩展,客户端就必然需要修改。于是就有了工厂方法模式的进化版——抽象工厂模式。抽象工厂模式改变了抽象工厂接口的结构:在工厂方法模式中,工厂类的方法只能实例化一种产品类;但是在抽象工厂模式中,抽象工厂接口包含了多个抽象方法,这些方法可以实例化不同的产品类。这样一来,在具体工厂类之中,就可以在不同的方法中实例化不同的产品类了。这样的好处就是,在某些情况下,客户端可以直接调用不同的具体工厂类的方法来实例化指定的产品类,而不再依赖逻辑选择了。

 

从直观上看,从简单工厂模式到工厂方法模式再到抽象工厂模式,单个类的职责在不断减少,类与类之间的联系也在不断简化,耦合度再不断降低;而另一方面,实现功能所需要的类的数量却在不断增加,维护难度在加大。在实际的应用中,究竟使用哪种模式来进行类实例化,个人认为更应该考虑模块未来的扩展性能有多大。假如对于不常扩展而且功能较为单一的模块,采用抽象工厂模式反倒有些费力不讨好。

 

另一方面,采用抽象工厂模式的时候,如果刻意不用逻辑选择进行判断,根据类名来进行实例化的话,感觉上跟直接调用业务类差别也不大。因此,实际上抽象工厂模式常常与另一个技术相配合使用,那就是前述的“某些情况”,也就是反射

 

所谓反射就是根据编程语言提供的反射类,直接将字符串转化为类或方法,然后再进行调用。这样一来,在抽象工厂模式中,程序员在客户端代码中可以不知道具体的类名,通过反射来将输入或者获取到的字符串转化为抽象工厂模式中的工厂类,再调用同名方法实例化产品类,这样一来就可以完全避免使用逻辑判断了。

 

再进一步,如果将这些字符串事先保存在代码外部的文件中(以规定的格式),那就是依赖注入技术了。这样就可以完全解除分支语句了。

你可能感兴趣的:(设计模式,编程,读书,扩展,语言,产品)