在创建型模式中,有3中关于工厂的模式,分别是:简单工厂模式,工厂方法模式,抽象工厂模式。这3中模式既有各自的优点,同时,这3中模式又可以逐步演化:如,简单工厂可以演化成工厂方法,工厂方法可以演化成抽象工厂。
简单工厂到工厂方法
由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。
另外,当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,造成switch..case过于复杂,很难避免模块功能的蔓延,对系统的维护和扩展非常不利。
就是说,switch..case这种判断一是增加新类时要修改switch语句,二如果产品太多,又造成switch过于复杂。
鉴于简单工厂中switch的这两个缺点,所以,提出创建一个单独的类来进行产品的创建。工厂方法定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法是将一个类的实例化延迟到其子类。
例如:
编写一个计算器,如果用简单工厂来写的话,就要在创建示例的工厂类中写很多switch语句,一旦增加新的运算,就要修改核心的代码,违反了开放封闭的原则。
public class OperationFactory { public static Operation createOperate(string operate) { Operation oper = null; switch (operate) { case "+": oper = new OperationAdd(); break; case "-": oper = new Operation(); break; case "*": oper = new Operation(); break; case "/": oper = new Operation(); break; } return oper; } }
但是如果改成用工厂方法来写的话,当增加运算时,只需在多加两个类,虽然没有避免掉判断,但是一旦扩展功能的话,本来是要改工厂类的,而现在修改的确是客户端。虽然增加了类,但是使得扩展更灵活。
总结:
工厂方法克服了简单工厂违背开放—封闭原则的缺点,又保持了封装对象创建过程的优点。
它们都是集中封装了对象的创建,使得要更换对象时,不需要做大的改动就可实现,降低了客户程序与产品对象的耦合。工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。
工厂方法到抽象工厂模式
先来看两种方法访问数据库的结构图:
用工厂方法访问数据库:
接着是抽象工厂访问数据库:
从图中可以看出,当用工厂方法访问数据库的时候,访问的是一张表,而当用抽象工厂访问数据库的时候访问的是两张表。如果去掉抽象工厂方法中访问第二张表的类,可以看出,它们剩下的部分是一样的。、
所以,从工程方法到抽象工厂,只是涉及到的产品系列多了。
简单工厂对抽象工厂的改进
从简单工厂到工厂方法,为了改进switch的不灵活创建了更多的类,从工厂方法到抽象工厂也是多了类,那么,如果使用抽象工厂时有非常多的product时就会出现问题:比如,现在有100张表,每个表都是一个product,要从access数据库换到sql server数据库,那么,要改动的这句“Ifactoryfacoty=new AccessFactory();”,改动100次了,这是件很悲伤的事儿。。这时,我们可以用简单工厂来改进抽象工厂。
简单工厂最大的弊端就是当增加新的需求时要改进switch,但是如果switch的可选项就是两项,不如,一个公司使用的数据库目前只有access和sql server时,这时,switch语句就是不用被经常改动的,此时,它的缺点恰恰成了它最大的优点,因为相比工厂方法和抽象工厂,它不用创建那么多的类就能很简单的实现选择问题。
如下结构图:
总的来说,这3种模式都是为了实现选择问题的模式。我们想要做到的就是在程序运行时根据需要做出正确选择,并且当程序日后遇到需求的改动,是非常容易扩展和修改的。
选择的算法好实现,但是可扩展,易修改却不好实现。为什么不好实现呢?还是因为代码写的太死了。
想想一起我们学习一门语言的时候,总会学到一个叫做变量的东西。这是个非常好的东西。因为它可以在程序运行时动态的赋值,改动。如果在选择的时候,我们有这样一个变量,只需给它一次初值,以后程序都根据这个变量的值去实例化对象,一旦要改动,只需改动一次就行。那么就会省去判断的麻烦,并且更加灵活。
这里,就要用到新技术了——反射。
这里,利用反射+字符串拼接,完美实现实例化对象。
小结
1,对于这3种涉及到工厂的方法,它们各有各的优点,要注意它们的使用条件,并不是抽象工厂模式就最好;
2,有时候,模式的混合使用会有更好的效果;
3,在设计中,要尽量的封装变化。