设计模式
🗒️工厂模式
00 min
2022-10-16
2023-7-31
type
status
date
slug
summary
tags
category
icon
password
😀
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
工厂模式主要是替代系统中生成复杂对象的部分,简单的生成对象可以使用new Instance()。在生成复杂对象时(指类的构造函数参数过多),可以将创建对象的过程用工厂模式代替,减少代码的耦合、带来更大的扩展性以及便于后期的维护。

一、简单工厂模式

简单工厂模式(Simple Fatory Pattern),又称静态工厂方法模式,属于类创建型模式。是可以根据参数的不同来返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
  • 优点:调用者想创建一个对象,只需知道其中参数就可以了。扩展性高(小有争议),增加一个产品只需扩展一个工厂就可以。屏蔽产品的具体实现(对象的创建逻辑),是的调用者只关心接口就行。
  • 缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
模式结构
  • ShapeFactory(工厂角色):工厂角色负责创建所有实例的内部逻辑。
  • Shape(抽象产品角色):抽象产品角色是所创建的对象的父类,负责描述所有实例所共有的公共接口。
  • Circle(具体产品角色):具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。
notion image

代码示例

抽象产品角色,创建对象的公共父类
具体产品角色,所要创建的具体对象实例
工厂角色
Test

总结

  • 使用的场景?
    • 对于一个产品种类相对较少,使用简单工厂模式可以很方便的创建所需要的产品。客户端使用简单工厂模式传入工厂类的参数,由工厂来完成创建对象的逻辑。
      消费者不关心它所要创建对象的类(产品类)的时候。
      消费者知道它所要创建对象的类(产品类),但不关心如何创建的时候。
  • 本质是什么?
    • 将实例化的操作单独放到一个类中,这个类就成为了简单工厂类,在简单工厂类中决定实例哪个具体子类。
  • 它解决了什么问题?
    • 将代码中复杂对象的创建过程抽离出来,降低代码的耦合度,提高整体扩展性以及便于后期维护。
  • 它体现了设计模式中什么原则?
  • 存在的缺陷?
    • 当增加新产品的时候,代码改动点过多。可观以上的工厂实现方式,当抽象产品下又增加新产品时,需要在工厂类中也增加if else程序,违反了开闭原则(对原有功能进行了修改),且工厂类中过多if else代码块显得代码十分臃肿,不利于维护。
      可使用反射进行优化,使用工厂类时,传入具体子类的类名。即使新增产品的时候,也不需要维护工厂类。但传入参数就固定了,也就是说消费者需要知道产品的类名(使情况使用吧)。
  • 你认为与它相关的设计模式有哪些? 它们之间的区别有哪些?
  • 开源架构中哪些使用了这一模式?
    • 简单工厂在JDK源码中举例(Calendar)
      • 简单工厂在Logback源码中的应用 Logback中的LoggerFactory,根据入参不同存在多个重载的getLogger方法

      二、工厂模式

      简单工厂模式中,一个工厂类中负责所有产品的创建,当增加新产品时,会涉及旧代码的改动,违反了开闭原则。而工厂模式中就优化了这点,工厂模式将之前的工厂类拆分,将具体产品的创建过程交给专门的工厂子类来完成。先定义一个抽象工厂类,再定义具体的工厂类来实现具体产品的创建逻辑,当增加新产品时,只需要为这个产品创建一个具体的工厂类就可以获得该产品的实例,更加符合开闭原则
      工厂方法模式(Factory Method Pattern)又称工厂模式,也叫虚拟构造器模式或者多态工厂模式,属于类创建型模式。在此模式中,工厂父类负责定义创建产品对象的公共接口,工厂子类负责生成具体的产品对象,目的是将产品类的实例化操作延迟到工厂子类中完成,通过工厂子类来确定应该实例化哪一个具体产品类。
      优点
      • 工厂模式中创建用户所需要的产品,向用户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
      • 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。使工厂可以自主确定创建何种产品对象,将如何创建这个对象的细节完全封装在具体工厂内部。
      • 系统的扩展性较好,符合“开闭原则”,在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。
      缺点
      • 添加新产品时,需要编写新的具体产品类,和与之对应的具体工厂类,系统中类的个数成对增加。在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
      • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
      模式结构
      • ICourseFactory:抽象工厂
      • PythonCourseFactory:具体工厂
      • ICourse:抽象产品
      • PythonCourse:具体产品
      工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责哪一个产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。
      notion image

      代码示例

      1. 产品类
      1. 工厂类

      总结

      适用场景
      • 一个类不知道它所需要的对象的类:客户端不需要知道具体产品类的类名,只需知道所对应的工厂即可,具体的产品对象由具体工厂类创建。客户端需要知道创建具体产品的工厂类。
      • 一个类通过其子类来指导创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏替换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
      • 将创建对象的任务委托给多个工厂类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时动态指定,可将具体工厂类的类名存储在配置文件或数据库中。
      模式扩展
      • 使用多个工厂方法:在抽象工厂角色中可以定义多个工厂方法,从而使具体工厂角色实现这些不同的工厂方法,这些方法可以包含不同的业务逻辑,以满足对不同的产品对象的需求。
      • 产品对象的重复使用:工厂对象将已经创建过的产品保存到一个集合(如数组、List等)中,然后根据客户对产品的请求,对集合进行查询。如果有满足要求的产品对象,就直接将该产品返回客户端;如果集合中没有这样的产品对象,那么就创建一个新的满足要求的产品对象,然后将这个对象在增加到集合中,再返回给客户端。
      • 多态性的丧失和模式的退化:如果工厂仅仅返回一个具体产品对象,便违背了工厂方法的用意,发生退化,此时就不再是工厂方法模式了。一般来说,工厂对象应当有一个抽象的父类型,如果工厂等级结构中只有一个具体工厂类的话,抽象工厂就可以省略,也将发生了退化。当只有一个具体工厂,在具体工厂中可以创建所有的产品对象,并且工厂方法设计为静态方法时,工厂方法模式就退化成简单工厂模式。

      三、抽象工厂模式

      抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。属于对象创建型模式,提供了一种创建对象的最佳方式。提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
      在工厂模式中一个具体工厂对应一种具体产品,工厂方法具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或一组重载的工厂方法。但是有时候是需要一个工厂可以提供多种产品对象。
      • 产品等级结构 :产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
      • 产品族 :在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。
      抽象工厂模式与工厂模式最大的区别在于:工厂模式针对的是一个产品等级结构,而抽象工厂模式是面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。抽象工厂模式比工厂模式更为简单、有效率。
      优点
      • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。这种隔离使得更换一个具体工厂变得相对容易,且抽象工厂模式可以实现高内聚低耦合的设计目的。
      • 当一个产品族中的多个对象被设计成一起工作时,它可以保证客户端始终只使用同一个产品族中的对象。
      • 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
      缺点
      • 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。
      • 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)。
      模式结构
      • AbstractFactory:抽象工厂
      • ConcreteFactory:具体工厂
      • AbstractProduct:抽象产品
      • Product:具体产品
      notion image

      代码示例

      1.工厂类
      1. 产品类
      1. 测试类
       
      上一篇
      单例设计模式
      下一篇
      原型模式