抽象工厂、工厂方法和简单工厂的不同点及使用心得
这三种工厂模式都属于创建型模式,它们的最终目的都是为了创建具体的产品类,同时封装具体的产品创建过程。
1、抽象工厂模式
先从抽象工厂说起,抽象工厂是从两个维度对创建一系列相关的复杂对象做封装和抽象[定义],这句看着有点晕吧^^,不急,下面这个例子会把这句话彻底的解释清楚。抽象工厂相对来说最复杂,而将抽象工厂一步一步做简化,首先就会得到工厂方法的结构,继而可以得到简单工厂的结构。
举个现实中的例子,比如生产汽车,由于生产汽车的品牌有很多,比如奔驰、宝马、大众等等,因此工厂将会有很多,此时我们就需要将这些工厂抽象出来产生一个工厂接口,而这个工厂接口不用去关心这些工厂具体怎么生产产品以及这些产品在不同的工厂之间的差异,他只需要定义出来生产车的哪些部件就好了,比如CreateWheel(车轮)、CreateFrame(车架)、CreateEngine(发动机)等,而不同的工厂由于工艺不同,它在具体制造这些产品的时候必然要重写这些方法,且具体实现方式在具体工厂间的差异可能非常大。由于我们最终的结果是要组装一辆车,这辆车每个部件的任务(接口)是我们早已定义好的,比如发动机的任务就是为车提供动力,而不能去随意完成别的任务(例如吹个冷风啥的),因此每个部件我们同样需要抽象出一个接口来定义它的规范。由于各个工厂间的工艺不同(具体实现不同),因此对于某种具体部件,每个工厂都需要实例化这个部件的接口,为这个部件提供一种具体的生产方式。
假设有m家工厂,n种部件,如果按照抽象工厂模式去设计的话,最终将会有1个抽象工厂接口(客户端用来初始化并决定具体用哪家工厂去生产产品),n个抽象部件接口(定义每个部件的规范标准,这些标准在各个工厂下都是一样的),m个具体工厂类(每个工厂有n个方法,用来初始化n个具体部件生产类),m*n个具体部件类(这些类是真正生产产品的类)。
抽象工厂类图
抽象工厂对于变化的封装:1、如果要切换工厂,只需要在最开始初始化工厂类的时候换另一家工厂就好了,而整个结构都无需改动。2、如果增加部件,抽象工厂接口以及其子工厂都需要添加能生产此部件的方法,同时还需要添加一个此部件的抽象接口以及每种工厂生产这种部件的具体方法,好处是已有的部件类不需要改动。3、如果增加工厂,首先需要增加此工厂并实现抽象工厂类,同时需要在每个抽象部件那里加一个此工厂生产对应部件的具体类,好处是已有工厂类和部件类都不需要改动。综上所述,抽象工厂模式基本上完美的遵循了开放封闭原则,即使第二种情况需要修改已有的工厂类,但由于工厂类的职责是去初始化并返回一个真正的部件生产类,因此已有的核心类部件类依然没有因为扩展而做过任何修改。
2、工厂方法模式
工厂方法可以说是抽象工厂的一个特例,当工厂里只有一种产品的时候,抽象工厂的结构就简化成工厂方法的结构了。此时会有一个抽象工厂接口,一个抽象产品接口,假设还是有m家工厂,那么会有m个具体工厂类,同时有m个具体产品类,工厂类和产品类是一一对应的关系,每个工厂类负责去初始化其对应的产品类。
工厂方法类图
工厂方法也是符合开放封闭原则的,如果再加一个新的工厂,只需要增加一个工厂类和此工厂生产产品的具体类就OK了,其他工厂类和产品类都无需改动。
3、简单工厂模式
简单工厂模式并没有AbstractFactory接口,它是根据参数或者配置文件等事先定义好的变量,然后利用分支判断或者反射技术来动态的初始化具体产品类并返回。它的产品类接口和数量与其他两种工厂模式一样,不同的地方在于它没有那么多的工厂类,可以只用一个静态工厂类来生成想要的产品。
由于增加工厂或者产品都需要修改静态工厂类,因此它不符合开放封闭原则。好处是大大减少了工厂类,若使用了反射技术,也会减少很多判断分支代码量。
使用场景总结:如果产品单一,并且客户端在创建产品实例时需要用灵活的参数来指定具体使用哪种工厂,那么可以优先使用简单工厂;若客户端相对稳定的指定一种工厂,同时在多个地方用此工厂创建产品类,则优先考虑用工厂方法模式。如果产品有多种,则考虑使用抽象工厂模式。需要注意的是抽象工厂模式里的工厂类既可以用工厂方法来实现,此时是标准的抽象工厂模式;也可用简单工厂来实现,这种情况一般是用一个静态工厂类和多个静态方法来代替那一大堆的工厂类,工厂种类的指定可以用常量或配置文件,并且在一定的环境下相对稳定。
用简单工厂简化后的抽象工厂
还需注意的一点是如果使用了简单工厂后,发现客户端频繁的调用简单工厂里的静态方法来生产相同工厂下的不同对象,此时就有必要用工厂方法模式来优化工厂类了。因为若一旦要换一家工厂生产对象时,客户端的改动将会很头疼,所有调用方都需要改动,而工厂方法只需要在初始化工厂类时修改成另一家工厂就OK了。
版权声明:本文为原创文章,转载请注明出处,谢谢~~