工厂模式

2019-03-04 1086 ℃

简单工厂模式

简单工厂模式(Simple Factory Pattern) 可以根据参数的不同返回不同类的实例。简单工厂把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个具体子类来实例化。

简单工厂模式又称为静态工厂方法(Static Factory Method)模式,简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。简单工厂模式不属于23种GOF设计模式之一。

结构

  • 工厂(Factory): 负责实现创建所有实例的内部逻辑,工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
  • 抽象产品(Product): 简单工厂模式所创建的所有对象的父类,负责描述所有实例所共有的公共接口。
  • 具体产品(ConcreteProduct): 简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。

简单工厂模式UML类图

优点

  • 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
  • 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
  • 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

缺点

  • 由于工厂类集中了所有产品创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中,一旦工厂类不能正常工作,整个系统都要受到影响。
  • 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
  • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
  • 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

适用场景

  • 工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
  • 客户端只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。

代码实现

设计一个CPU工厂,根据传入的参数决定生产的是AMD的CPU还是英特尔的CPU。

CPU接口(抽象产品)

public interface Cpu { /** * 获得CPU描述信息 * @return 描述信息 */ public String getCpu(); }

CPU实现类(具体产品)

public class AmdCpu implements Cpu { @Override public String getCpu() { return "AMD的CPU"; } }
public class IntelCpu implements Cpu { @Override public String getCpu() { return "Intel的CPU"; } }

CPU工厂类(工厂)

public class CpuFactory { /** * 根据参数决定要生产的是Intel的CPU还是AMD的CPU * @param isIntelCpu 是否生产Intel的CPU * @return 生产的CPU */ public Cpu createCpu(boolean isIntelCpu){ if(isIntelCpu){ //生产Intel的CPU return new IntelCpu(); }else{ //生产AMD的CPU return new AmdCpu(); } } }

测试

public class test { public static void main(String[] args) { //实例化CPU工厂 CpuFactory cpuFactory=new CpuFactory(); //生产Intel的CPU Cpu intelCpu=cpuFactory.createCpu(true); System.out.println(intelCpu.getCpu()); //生产AMD的CPU Cpu amdCpu=cpuFactory.createCpu(false); System.out.println(amdCpu.getCpu()); } }

输出结果

Intel的CPU
AMD的CPU

工厂方法模式

定义

工厂方法模式(Factory Method Pattern) 定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

工厂方法模式又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责哪一个产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。

结构

  • 抽象工厂(Factory): 声明了工厂方法,用于返回一个产品,是工厂方法模式的核心,任何在模式中创建对象的工厂类都必须实现该接口。
  • 具体工厂(ConcreteFactory): 抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户调用,返回一个具体产品类的实例。
  • 抽象产品(Product): 工厂方法模式所创建的对象的超类,也就是产品对象的共同父类或共同拥有的接口。
  • 具体产品(ConcreteProduct): 实现了抽象产品角色所定义的接口。某具体产品由专门的具体工厂创建,它们之间往往一一对应。

工厂方法模式UML类图

优点

  • 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
  • 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类。
  • 扩展性高,在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。

缺点

  • 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
  • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。

适用场景

  • 一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
  • 一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
  • 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。

代码实现

设计一个显卡抽象工厂,各显卡工厂继承此抽象工厂生产自家的显卡。

显卡接口(抽象产品)

public interface Gpu { /** * 获得显卡描述信息 * @return 描述信息 */ public String getGpu(); }

显卡实现类(具体产品)

public class NvidiaGpu implements Gpu { @Override public String getGpu() { return "NVIDIA的显卡"; } }
public class AmdGpu implements Gpu { @Override public String getGpu() { return "AMD的显卡"; } }

显卡工厂接口(抽象工厂)

public interface GpuFactory { /** * 生产显卡的方法 * @return 显卡 */ public Gpu createGpu(); }

显卡工厂实现类(具体工厂)

public class NvidiaGpuFactory implements GpuFactory { @Override public Gpu createGpu() { //生产NVIDIA的显卡 return new NvidiaGpu(); } }
public class AmdGpuFactory implements GpuFactory { @Override public Gpu createGpu() { //生产AMD的显卡 return new AmdGpu(); } }

测试

public class test { public static void main(String[] args) { //实例化NVIDIA显卡工厂 GpuFactory nvidiaGpuFactory=new NvidiaGpuFactory(); //生产NVIDIA的显卡 Gpu nvidiaGpu=nvidiaGpuFactory.createGpu(); System.out.println(nvidiaGpu.getGpu()); //实例化AMD显卡工厂 GpuFactory amdGpuFactory=new AmdGpuFactory(); //生产AMD的显卡 Gpu amdGpu=amdGpuFactory.createGpu(); System.out.println(amdGpu.getGpu()); } }

输出结果

NVIDIA的显卡
AMD的显卡

抽象工厂模式

定义

抽象工厂模式(Abstract Factory Pattern) 提供一个接口,用于创建相关或萤爱对象的家族,而不需要明确指定具体类。

抽象工厂模式又称为Kit模式,当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式。抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形态。

结构

  • 抽象工厂(Factory): 声明生成抽象产品的方法。
  • 具体工厂(ConcreteFactory): 实现了抽象工厂中声明的生成抽象产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
  • 抽象产品(Product): 为每种产品声明接口,定义产品的抽象业务方法。
  • 具体产品(ConcreteProduct): 生产的具体产品对象,实现抽象产品接口中定义的业务方法。

抽象工厂模式UML类图

优点

  • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,应用抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。
  • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是一种非常实用的设计模式。
  • 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。

缺点

  • 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。
  • 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)。

适用场景

  • 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。
  • 系统中有多于一个的产品族,而每次只使用其中某一产品族。
  • 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
  • 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

代码实现

电脑外设有键盘、鼠标等,不同电脑厂商生产不同的键盘、鼠标。

电脑外设接口(抽象产品)

public interface Mouse { /** * 获得鼠标描述信息 * @return 描述信息 */ public String getMouse(); }
public interface Keyboard { /** * 获得键盘描述信息 * @return 描述信息 */ public String getKeyboard(); }

电脑外设实现类(具体产品)

public class AsusKeyboard implements Keyboard { @Override public String getKeyboard() { return "华硕的键盘"; } }
public class AsusMouse implements Mouse { @Override public String getMouse() { return "华硕的鼠标"; } }
public class LenovoKeyboard implements Keyboard { @Override public String getKeyboard() { return "联想的键盘"; } }
public class LenovoMouse implements Mouse { @Override public String getMouse() { return "联想的鼠标"; } }

电脑外设工厂接口(抽象工厂)

public interface PeripheralFactory { /** * 生产鼠标的方法 * @return 鼠标 */ public Mouse createMouse(); /** * 生产键盘的方法 * @return 键盘 */ public Keyboard createKeyboard(); }

电脑外设工厂实现类(具体工厂)

public class AsusPeripheralFactory implements PeripheralFactory { @Override public Mouse createMouse() { //华硕鼠标 return new AsusMouse(); } @Override public Keyboard createKeyboard() { //华硕键盘 return new AsusKeyboard(); } }
public class LenovoPeripheralFactory implements PeripheralFactory { @Override public Mouse createMouse() { //联想鼠标 return new LenovoMouse(); } @Override public Keyboard createKeyboard() { //联想键盘 return new LenovoKeyboard(); } }

测试

public class test { public static void main(String[] args) { //实例化华硕外设工厂 PeripheralFactory asusPeripheralFactory=new AsusPeripheralFactory(); //生产华硕鼠标 Mouse asusMouse=asusPeripheralFactory.createMouse(); System.out.println(asusMouse.getMouse()); //生产华硕键盘 Keyboard asusKeyboard=asusPeripheralFactory.createKeyboard(); System.out.println(asusKeyboard.getKeyboard()); //实例化联想外设工厂 PeripheralFactory lenovoPeripheralFactory=new LenovoPeripheralFactory(); //生产联想鼠标 Mouse lenovoMouse=lenovoPeripheralFactory.createMouse(); System.out.println(lenovoMouse.getMouse()); //生产华硕键盘 Keyboard lenovoKeyboard=lenovoPeripheralFactory.createKeyboard(); System.out.println(lenovoKeyboard.getKeyboard()); } }

输出结果

华硕的鼠标
华硕的键盘
联想的鼠标
联想的键盘

区别

简单工厂模式与工厂方法模式

工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。

工厂方法模式与抽象工厂模式

抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。

  • 产品等级结构 :产品等级结构即产品的继承结构,如一个抽象类是鼠标,其子类有华硕鼠标、联想鼠标、戴尔鼠标等,则抽象鼠标与具体品牌的鼠标之间构成了一个产品等级结构,抽象鼠标是父类,而具体品牌的鼠标是其子类。
  • 产品族 :在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如华硕工厂生产的华硕鼠标、华硕键盘、华硕主板等,华硕鼠标位于鼠标产品等级结构中,华硕键盘位于键盘产品等级结构中。
版权声明:周华个人博客原创文章,转载请注明出处。

文章链接:http://www.iszhouhua.com/factory-pattern.html

发表时间:2019-03-04 23:28

最后更新时间:2019-03-05 22:40