设计模式辨析——工厂篇(简单工厂、静态工厂、工厂方法、抽象工厂)
| 2023-12-29
0  |  阅读时长 0 分钟
日期
Mar 5, 2022
Tags
设计模式
面向对象

导语

设计模式(Design Pattern)是软件开发过程中一般问题的解决方案,是无数面向对象软件开发人员的经验总结,对于软件设计开发十分重要。然而由于设计模式种类繁多,内容偏理论,缺乏开发经验对于相关概念的理解也比较困难,同时其中不乏很多类型相似的设计模式,更是让对设计模式的学习难上加难。我之前学习过设计模式,但学完就忘,只记下了工厂方法模式几个比较经典的模式。
最近一直在阅读《Head First 设计模式》和《大话设计模式》两本书,为了巩固对于设计模式的理解,了解不同设计模式的特点,现将学习过程中的笔记总结在「设计模式辨析」,相关引用参考将在文末指出。

工厂

找出会变化的部分,把它们从不变的部分分离出来
当软件开发过程中使用接口时,代码中往往需要实例化大量的具体类,而这些实现大多是由一些条件决定的。对于如何实例化对象这个问题,往往考虑用一个单独的类来处理创造实例的过程,这个类就是工厂(factory)

什么是工厂

针对接口编程,不针对实现编程
定义:用于封装创建对象的代码,负责处理创建对象的细节的类被称为工厂(Factory)
优点:将创建对象的代码集中在一个对象或方法中,避免代码中的重复,便于以后的维护

简单工厂「模式」(Simple Factory「Pattern」)

简单工厂「模式」是对于工厂最基础的应用,但它其实不能算作“工厂模式”,它不是一个设计模式,像是一种编程习惯。

简单工厂代码示例:简单计算器[3]

通过代码实现一个简单计算器,具有加减乘除的运算功能
开放—封闭原则:对扩展开放,对修改关闭

优点:

  1. 根据客户端的选择条件动态实例化相关的类,去除了客户端与具体类的依赖。
  1. 添加新的类只需要在工厂类中添加新的分支

缺点:

  1. 不符合“开放—封闭原则”,简单工厂中每一次扩展都需要对工厂类进行修改

静态工厂模式

将工厂类中的创建对象的功能定义为静态的,就是静态工厂模式,它同样不是一种设计模式。

特点:

  1. 不需要使用创建对象的方法实例化对象
  1. 不能通过继承来改变创建方法的行为
由于静态工厂与简单工厂的差别不大,在此就不详细展开。关于静态工厂模式更多的内容这篇文章中有详细描述「https://zhuanlan.zhihu.com/p/157099580」,感兴趣可以了解。

工厂方法模式(Factory Method Pattern)

什么是工厂方法模式?

工厂方法模式定义了一个创建对象的接口,让子类决定要实例化的类是哪一个,工厂方法把一个类的实例化推迟到其子类

工厂方法模式代码示例:简单计算器[3]

通过代码实现一个简单计算器,具有加减乘除的运算功能

优点

  1. 通过让工厂子类决定应该创建的对象是什么,来达到将对象创建的过程封装的目的。
  1. 针对接口编程,不针对实现编程,代码更具弹性,扩展性更好
  1. 符合开放-封闭原则:客户端决定实例化哪一个工厂来创建类,在扩展时不需要修改工厂类
  1. 解耦合:把创建对象的具体实现移到具体的工厂子类,在工厂接口类并不需要知道实际创建的对象是哪一个类,解耦了客户端中关于超类的代码和子类对象创建代码。

与简单工厂的异同:

同:

  1. 集中封装了对象的创建,降低客户端对特定实现的依赖以及与产品对象的耦合

异:

  1. 简单工厂把有关实例化的全部事情,都在工厂类中处理(没有抽象工厂类),然而工厂方法模式创建了一个框架,让工厂子类决定要如何实现。
  1. 克服了简单工厂违背“开放-封闭原则”的缺点,又保持了封装对象创建过程的优点,对简单工厂的进一步抽象和推广

抽象工厂模式(Abstract Factory Pattern)

依赖倒置原则:要依赖抽象,不要依赖具体的类
  • 避免在OO设计中违反依赖倒置原则的指导方针:
    • 变量不可以持有具体类的引用
    • 不要让类派生自具体类
    • 不要覆盖基类中已实现的方法

什么是抽象工厂模式?

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而不需要指明它们具体的类。
抽象工厂中的每一个方法创建一个具体类,实际利用工厂方法实现

抽象工厂模式代码示例:计算器生产

假设现在有流水线负责生产计算器按钮,并对计算器进行组装、检查,计算器按钮的颜色系列有黑色系列、白色系列等需要实现
🟧
需要注意的是,由于抽象工厂类的使用场景针对「系列」,所以这里代码示例的场景发生了改变,涉及类比较多,请一定搞清楚。其中抽象工厂类的主要作用是把不同系列的按钮创建封装在了一起,因此在改变计算器的按钮系列时,我们只需要更换流水线类就好了(流水线类在这里其实只是工厂类上的一个封装,可以简单理解为更换了工厂类)。你可以设想一下,要是使用的是简单工厂、工厂方法模式,要想实现上述代码示例的功能,代码应该怎么写?改动按钮系列时,需要改动那些地方?

优点

  1. 易于交换产品系列,改变具体工厂类只需要在初始化时进行,十分方便就可以使用不同产品配置
  1. 允许客户使用抽象的接口创建具体的一组产品,创建过程与客户端分离,降低耦合度

缺点

  1. 增加需求时需要改动接口,对每一个具体工厂类进行改动,较为复杂

与工厂方法模式的异同:

同:

  1. 集中封装了对象的创建,降低客户端对特定实现的依赖以及与产品对象的耦合

异:

  1. 创建对象
      • 工厂方法模式:继承
        • 通过工厂子类创建对象,客户端只需要知道具体的抽象类型,由工厂子类决定具体类型,只负责将客户从具体类型中解耦
      • 抽象工厂模式:对象的组合
        • 提供用来创建一个产品家族的抽象类,这个类型的子类定义产品被创建的方法,使用时通过实例化具体工厂类,并将工厂类传入针对抽象类型写的代码中,把客户从所使用的实际具体产品中解耦
  1. 抽象工厂集合了一群相关的产品类,而工厂方法只需要创建一个产品。抽象工厂中的每一个方法创建一个具体类,实际是利用工厂方法实现,

拓展

  • 利用简单工厂改进抽象工厂:
    • 减少具体工厂类,达到解耦目的
  • 反射+抽象工厂:
    • 利用依赖注入消除switch的使用

总结

对于使用到工厂的设计模式,在理解使用场景和概念后,只要记住以下几句话就可以确保掌握了。
  1. 所以工厂都是用来封装对象的创建
  1. 所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合
  1. 工厂帮助我们针对抽象编程,而不是针对具体类编程
 

Reference:

[1] 程杰. 大话设计模式[M/OL]. 清华大学出版社 2007-12-1, 2007.
[2] FREEMAN E, FREEMAN E, BATES B, 等. Head First 设计模式(中文版)[M/OL]. TAIWAN公司 O, 译. 中国电力出版社, 2007.
 
Loading...
目录