概述
工厂顾名思义就是创建产品,根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式,根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。该模式用于封装和管理对象的创建,是一种创建型模式。本文从一个具体的例子逐步深入分析,来体会三种工厂模式的应用场景和利弊
简单工厂
介绍
简单工厂模式又叫静态工厂方法(Static Factory Method)是属于创建型模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪种产品的实例。简单工厂模式是工厂模式家族最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。
适用场景
简单工厂适合产品对象较少,且产品固定的需求
简单工厂实现
该模式对对象创建管理方式最为简单,因为其仅仅简单的对不同类对象的创建进行了一层薄薄的封装。该模式通过向工厂传递类型来指定要创建的对象:
Phone类 :手机标准规范类(AbstractProduct)
public interface Phone {
void make();
}
MiPhone类 :制造小米手机(Product1)
public class MiPhone implements Phone {
@Override
public void make() {
System.out.println("make xiaomi phone!");
}
}
IPhone类 :制造苹果手机(Product2)
public class MiPhone implements Phone {
@Override
public void make() {
System.out.println("make xiaomi phone!");
}
}
PhoneFactory类 :手机代工厂(Factory)
public class PhoneFactory {
/**
* 创建手机
* @param phoneType MiPhone,iPhone
* @return
*/
public Phone makePhone(String phoneType){
if(phoneType.equalsIgnoreCase("MiPhone")){
return new MiPhone();
}
else if(phoneType.equalsIgnoreCase("iPhone")) {
return new IPhone();
}
return null;
}
}
演示 :
public class Demo {
public static void main(String[] args) {
PhoneFactory factory = new PhoneFactory();
// make xiaomi phone!
MiPhone miPhone = (MiPhone) factory.makePhone("MiPhone");
miPhone.make();
// make iphone!
IPhone iPhone = (IPhone)factory.makePhone("iPhone");
iPhone.make();
}
}
优点 & 缺点
优点:简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。明确区分了各自的职责和权力,有利于整个软件体系结构的优化。
缺点:很明显工厂类集中了所有实例的创建逻辑,容易违反GRASPR的高内聚的责任分配原则
工厂方法模式
介绍
工厂方法模式(Factory Method)又称多态性工厂模式。在工厂方法模式中,核心的工厂类不再负责所以产品的创建,而是将具体创建的工作交给子类去做。该核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品应当被实例化的细节。
适用场景
工厂方法模式是简单工厂的衍生,解决了许多简单工厂的问题。首先完全实现“开-闭原则”,实现了可扩展。其次更复杂的层次结构,可以应用于产品结构复杂的场合
工厂方法实现
和简单工厂模式中工厂负责生产所有产品相比,工厂方法模式将生成具体产品的任务分发给具体的产品工厂:
也就是定义一个抽象工厂,其定义了产品的生产接口,但不负责具体的产品,将生产任务交给不同的派生类工厂。这样不用通过指定类型来创建对象了。
接下来继续使用生产手机的例子来讲解该模式。
其中和产品相关的Phone类、MiPhone类和IPhone类的定义不变
AbstractFactory类 :生产不同产品的工厂的抽象类
public interface AbstractFactory {
Phone makePhone();
}
XiaoMiFactory类 :生产小米手机的工厂(ConcreteFactory1)
public class XiaoMiFactory implements AbstractFactory {
@Override
public Phone makePhone() {
return new MiPhone();
}
}
AppleFactory类 :生产苹果手机的工厂(ConcreteFactory2)
public class AppleFactory implements AbstractFactory {
@Override
public Phone makePhone() {
return new IPhone();
}
}
演示 :
public class Demo {
public static void main(String[] args) {
AbstractFactory miFactory = new XiaoMiFactory();
AbstractFactory appleFactory = new AppleFactory();
// make xiaomi phone!
MiPhone miPhone= (MiPhone) miFactory.makePhone();
miPhone.make();
// make iphone!
IPhone iPhone= (IPhone) appleFactory.makePhone();
iPhone.make();
}
}
优点 & 缺点
优点:
- 子类提供挂钩。基类为工厂方法提供缺省实现,子类可以重写新的实现,也可以继承父类的实现。
- 加一层间接性,增加了灵活性
- 屏蔽产品类。产品类的实现如何变化,调用者都不需要关心,只需关心产品的接口,只要接口保持不变,系统中的上层模块就不会发生变化
- 典型的解耦框架。高层模块只需要知道产品的抽象类,其他的实现类都不需要关心,符合迪米特法则,符合依赖倒置原则,符合里氏替换原则。
- 多态性:客户代码可以做到与特定应用无关,适用于任何实体类
缺点:
需要Creator和相应的子类作为factory method的载体,如果应用模型确实需要creator和子类存在,则很好;否则的话,需要增加一个类层次
抽象工厂模式(Abstract Factory)
上面两种模式不管工厂怎么拆分抽象,都只是针对一类产品Phone(AbstractProduct),如果要生成另一种产品PC,应该怎么表示呢?
最简单的方式是把2中介绍的工厂方法模式完全复制一份,不过这次生产的是PC。但同时也就意味着我们要完全复制和修改Phone生产管理的所有代码,显然这是一个笨办法,并不利于扩展和维护。
抽象工厂模式通过在AbstarctFactory中增加创建产品的接口,并在具体子工厂中实现新加产品的创建,当然前提是子工厂支持生产该产品。否则继承的这个接口可以什么也不干。
从上面类图结构中可以清楚的看到如何在工厂方法模式中通过增加新产品接口来实现产品的增加的。
接下来我们继续通过小米和苹果产品生产的例子来解释该模式。
为了弄清楚上面的结构,我们使用具体的产品和工厂来表示上面的UML类图,能更加清晰的看出模式是如何演变的:
适用场景
当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点
抽象工厂实现
PC类 :定义PC产品的接口(AbstractPC)
public interface PC {
void make();
}
MiPC类 :定义小米电脑产品(MIPC)
public class MiPC implements PC{
@Override
public void make() {
System.out.println("make xiaomi PC!");
}
}
MAC类 :定义苹果电脑产品(MAC)
public class MAC implements PC{
@Override
public void make() {
System.out.println("make MAC!");
}
}
下面需要修改工厂相关的类的定义:
AbstractFactory类 :增加PC产品制造接口
public interface AbstractFactory {
Phone makePhone();
PC makePC();
}
XiaoMiFactory类 :增加小米PC的制造(ConcreteFactory1)
public class XiaoMiFactory implements AbstractFactory {
@Override
public Phone makePhone() {
return new MiPhone();
}
@Override
public PC makePC() {
return new MiPC();
}
}
AppleFactory类 :增加苹果PC的制造(ConcreteFactory2)
public class AppleFactory implements AbstractFactory {
@Override
public Phone makePhone() {
return new IPhone();
}
@Override
public PC makePC() {
return new MAC();
}
}
演示 :
public class Demo {
public static void main(String[] args) {
AbstractFactory miFactory = new XiaoMiFactory();
AbstractFactory appleFactory = new AppleFactory();
// make xiaomi phone!
MiPhone miPhone = (MiPhone) miFactory.makePhone();
miPhone.make();
// make xiaomi PC!
MiPC miPC = (MiPC) miFactory.makePC();
miPhone.make();
// make iphone!
IPhone iPhone = (IPhone) appleFactory.makePhone();
iPhone.make();
// make MAC!
MAC mac = (MAC) appleFactory.makePC();
mac.make();
}
}
优点 & 缺点
优点:
抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束。所谓的产品族,一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理
缺点:
产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的