工厂方法模式
定义
在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
模式结构
- Product:抽象产品
- ConcreteProduct:具体产品
- Factory:抽象工厂
- ConcreteFactory:具体工厂
优点
- 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
- 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类。
- 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
缺点
- 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
实例
背景:小成有一间塑料加工厂(仅生产A类产品);随着客户需求的变化,客户需要生产B类产品;
冲突:改变原有塑料加工厂的配置和变化非常困难,假设下一次客户需要再发生变化,再次改变将增大非常大的成本;
解决方案:小成决定置办塑料分厂B来生产B类产品;
创建抽象工厂类,定义具体工厂的公共接口
1 | abstract class Factory{ |
创建抽象产品类 ,定义具体产品的公共接口;
1 | abstract class Product{ |
创建具体产品类(继承抽象产品类), 定义生产的具体产品;
1 | //具体产品A类 |
创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
1 | //工厂A类 - 生产A类产品 |
外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
1 | //生产工作流程 |
简单工厂模式违背了开闭原则:当需要添加新产品时,需要在工厂类的静态方法中添加新产品的创建逻辑,这样就修改了原来的代码,复用性降低。 工厂方法模式:将简单工厂模式中的工厂类用继承的方式细分。具体操作是,当需要添加新产品时,需要添加具体产品类和具体工厂类,这样完美解决了简单工厂违背开闭原则的问题。主要优点是,客户端不需要知道具体产品类的类名,只需要知道对应的工厂类。缺点是,增加一个新产品,需要增加一个新产品类和一个具体工厂类,类种类成对增加。
原型模式
原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类。
原型模式将克隆过程委派给被克隆的实际对象。 模式为所有支持克隆的对象声明了一个通用接口, 该接口让你能够克隆对象, 同时又无需将代码和对象所属类耦合。 通常情况下, 这样的接口中仅包含一个 克隆方法。
所有的类对克隆方法的实现都非常相似。 该方法会创建一个当前类的对象, 然后将原始对象所有的成员变量值复制到新建的类中。 你甚至可以复制私有成员变量, 因为绝大部分编程语言都允许对象访问其同类对象的私有成员变量。
模式结构
客户(Client)角色:客户类提出创建对象的请求;
抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java
接口或者Java
抽象类实现。此角色定义了的具体原型类所需的实现的方法。
具体原型(Concrete Prototype)角色:此角色需要实现抽象原型角色要求的克隆相关的接口。
1 | /** |
1 | public class ConcretePrototype1 extends Prototype { |
优点
1、将产品的创建过程封装起来,客户端不需要了解产品的具体创建流程。
2、利用Java的clone方法来创建对象肯定要比使用new来创建对象快很多,尤其是那些很复杂的对象的时候。
3、可以在不修改其他代码的情况下添加新的产品,符合“开-闭”原则。
缺点
原型模式的最大缺点就是每一个类必须都有一个clone方法,如果这个类的组成不太复杂的话还比较好,如果类的组成很复杂的话,如果想实现深度复制就非常困难了。