15.工厂模式

定义

简单工厂模式

  • 专门定义一个类来负责创建其他类的实例,根据参数的不同创建不同类的实例,被创建的实例通常具有共同的父类,这个模式叫简单工厂模式(Simple Factory Pattern)
  • 简单工厂模式又称为静态工厂方法模式。之所以叫“静态”,是因为在很多静态语言(如 Java、C++)中方法通常被定义成一个静态(static)方法,这样便可通过类名来直接调用方法。
  • 这是最简单的一个版本,只有一个工厂类 SimpleFactory,类中有一个静态的创建方法 createProduct,该方法根据参数传递过来的类型值(type)或名称(name)来创建具体的产品(子类)对象。
  • 定义:定义一个创建对象(实例化对象)的接口,通过参数来决定创建哪个类的实例。
  • 类图
  • 优缺点
    • 优点:
      • 实现简单、结构清晰。
      • 抽象出一个专门的类来负责某类对象的创建,分割出创建的职责,不能直接创建具体的对象,只需传入适当的参数即可。
      • 使用者可以不关注具体对象的类名称,只需知道传入什么参数可以创建哪些需要的对象。
    • 缺点:
      • 不易拓展,一旦添加新的产品类型,就不得不修改工厂的创建逻辑。不符合“开放 – 封闭”原则,如果要增加或删除一个产品类型,就要修改 switch … case …(或 if … else …)的判断代码。
      • 当产品类型较多时,工厂的创建逻辑可能过于复杂,switch … case …(或 if … else …)判断会变得非常多。一旦出错可能造成所有产品创建失败,不利于系统的维护。
  • 应用场景
    • 产品具有明显的继承关系,且产品的类型不太多。
    • 所有的产品具有相同的方法和类似的属性,使用者不关心具体的类型,只希望传入合适的参数能返回合适的对象。

工厂方法模式

  • 工厂方法模式是简单工厂模式的一个升级版本,为解决简单工厂模式不符合“开放 – 封闭”原则的问题,我们对 SimpleFactory 进行了一个拆分,抽象出一个父类 Factory,并增加多个子类分别负责创建不同的具体产品。
  • 定义:定义一个创建对象(实例化对象)的接口,让子类来决定创建哪个类的实例。工厂方法使一个类的实例化延迟到其子类。
  • 类图
    • Product 是要创建的产品的抽象类,ProductA 和 ProductB 是具体的产品类型。Factory 是所有工厂的抽象类,负责定义统一的接口。ProductAFactory 和 ProductBFactory 是具体的工厂类,分别负责产品 ProductA 和 ProductB 的创建。
  • 优缺点
    • 优点:
      • 解决了简单工厂模式不符合“开放 – 封闭”原则的问题,使程序更容易拓展。
      • 实现简单。
    • 缺点:
      • 对于有多种分类的产品,或具有二级分类的产品,工厂方法模式并不适用。
  • 多种分类:如我们有一个电子白板程序,可以绘制各种图形,那么画笔的绘制功能可以理解为一个工厂,而图形可以理解为一种产品;图形可以根据形状分为直线、矩形、椭圆等,也可以根据颜色分为红色图形、绿色图形、蓝色图形等。
  • 二级分类:如一个家电工厂,它可能同时生产冰箱、空调和洗衣机,那么冰箱、空调、洗衣机属于一级分类;而洗衣机又可分为高效型的和节能型的,高效型洗衣机和节能型洗衣机就属于二级分类。
  • 应用场景
    • 客户端不知道它所需要的对象的类。
    • 工厂类希望通过其子类来决定创建哪个具体类的对象。因为工厂方法模式简单且易拓展,因此在项目中应用得非常广泛,在很多标准库和开源项目中都能看到它的影子。

抽象工厂模式

  • 抽象工厂模式是工厂方法模式的升级版本,工厂方法模式不能解决具有二级分类的产品的创建问题,抽象工厂模式就是用来解决这一问题的。
  • 定义:提供一个创建一系列相关或相互依赖的对象的接口,而无须指定它们的具体类。
  • 类图
    • 抽象工厂模式适用于有多个系列且每个系列有相同子分类的产品。我们定义一个抽象的工厂类 AbstractFactory,AbstractFactory 中定义生产每个系列产品的方法;而两个具体的工厂实现类 Factory1 和 Factory2 分别生产子分类 1 的每一系列产品和子分类 2 的每一系列产品。
  • 优缺点
    • 优点
      • 解决了具有二级分类的产品的创建。
    • 缺点
      • 如果产品的分类超过二级,如三级甚至更多级,抽象工厂模式将会变得非常臃肿。
      • 不能解决产品有多种分类、多种组合的问题。
  • 应用场景
    • 系统中有多于一个的产品族,而每次只使用其中某一产品族。
    • 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。

进一步思考

  • 如果产品出现三级甚至更多级分类怎么办?
    • 如果程序中出现了三级分类的对象,就需要重新审视一下你的设计,看一下有些类是不是可以进行归纳、抽象合并。如果实际的应用场景中确实有三级甚至更多级分类,建议你不要使用工厂模式了,直接交给每一个具体的产品类自己去创建吧!因为超过三级(含三级)以上分类,会使工厂类变得非常臃肿而难以维护,开发成本也会急剧增加。模式是死的,人是活的,不要为了使用设计模式而使用设计模式!
  • 如果产品有多种分类、多种组合怎么办?
    • 如果产品有多种分类,就不能单独使用工厂模式了,需要结合其他的设计模式进行优化。如 15.5 节的白板程序,既有形状的分类又有颜色的分类,可以结合桥接模式(参见 20.2 节)一起使用,用桥接模式来定义产品,再用工厂模式来创建产品。

实战应用

from abc import ABCMeta, abstractmethod  
# 引入ABCMeta和abstractmethod来定义抽象类和抽象方法  
from enum import Enum  
  
  
# Python3.4 之后支持枚举Enum的语法  
  
class PenType(Enum):  
    """画笔类型"""  
    PenTypeLine = 1  
    PenTypeRect = 2  
    PenTypeEllipse = 3  
  
  
class Pen(metaclass=ABCMeta):  
    """画笔"""  
  
    def __init__(self, name):  
        self.__name = name  
  
    @abstractmethod  
    def getType(self):  
        pass  
  
    def getName(self):  
        return self.__name  
  
  
class LinePen(Pen):  
    """直线画笔"""  
  
    def __init__(self, name):  
        super().__init__(name)  
  
    def getType(self):  
        return PenType.PenTypeLine  
  
  
class RectanglePen(Pen):  
    """矩形画笔"""  
  
    def __init__(self, name):  
        super().__init__(name)  
  
    def getType(self):  
        return PenType.PenTypeRect  
  
  
class EllipsePen(Pen):  
    """椭圆画笔"""  
  
    def __init__(self, name):  
        super().__init__(name)  
  
    def getType(self):  
        return PenType.PenTypeEllipse  
  
  
class PenFactory:  
    """画笔工厂类"""  
  
    def __init__(self):  
        "定义一个字典(key:PenType,value:Pen)来存放对象,确保每一个类型只会有一个对象"  
        self.__pens = {}  
  
    def getSingleObj(self, penType, name):  
        """获得唯一实例的对象"""  
  
    def createPen(self, penType):  
        """创建画笔"""  
        if self.__pens.get(penType) is None:  
            # 如果该对象不存在,则创建一个对象并存到字典中  
            if penType == PenType.PenTypeLine:  
                pen = LinePen("直线画笔")  
            elif penType == PenType.PenTypeRect:  
                pen = RectanglePen("矩形画笔")  
            elif penType == PenType.PenTypeEllipse:  
                pen = EllipsePen("椭圆画笔")  
            else:  
                pen = Pen("")  
            self.__pens[penType] = pen  
        # 否则直接返回字典中的对象  
        return self.__pens[penType]  
  
  
def testPenFactory():  
    factory = PenFactory()  
    linePen = factory.createPen(PenType.PenTypeLine)  
    print("创建了 %s,对象id:%s, 类型:%s" % (linePen.getName(), id(linePen), linePen.getType()))  
    rectPen = factory.createPen(PenType.PenTypeRect)  
    print("创建了 %s,对象id:%s, 类型:%s" % (rectPen.getName(), id(rectPen), rectPen.getType()))  
    rectPen2 = factory.createPen(PenType.PenTypeRect)  
    print("创建了 %s,对象id:%s, 类型:%s" % (rectPen2.getName(), id(rectPen2), rectPen2.getType()))  
    ellipsePen = factory.createPen(PenType.PenTypeEllipse)  
    print("创建了 %s,对象id:%s, 类型:%s" % (ellipsePen.getName(), id(ellipsePen), ellipsePen.getType()))  
  
  
testPenFactory()
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇