创建型模式的作用就是创建对象,说到创建一个对象,最熟悉的就是 new 一个对象,然后 set 相关属性。但是,在很多场景下,我们需要给客户端提供更加友好的创建对象的方式,尤其是那种我们定义了类,但是需要提供给其他开发者用的时候。
总的来说就是对象实例化的模式,创建型模式用于解耦对象的实例化过程。
共分为5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
简单工厂模式
不直接向高层代码暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例
角色
工厂角色(Creator)
抽象产品角色(Product)
具体产品角色(Concrete Product)
优点
缺点
- 违反了单一职责原则,将创建逻辑集中到一个工厂类中
- 当添加新产品时,需要修改工厂类代码,违反了开闭原则
示例
从示例可以看出来,具体产品的对象创建全部封装到了工厂类中,高层代码操作时并不需要知道对象创建的具体细节,有新的产品添加时,只需要适当修改工厂类即可,但同时将所有创建逻辑都集中到了一个工厂类中,违反了单一原则,且每当有新产品添加时就要修改工厂类代码,违反了开闭原则。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| from abc import ABCMeta, abstractmethod
class Payment(metaclass=ABCMeta): """抽象产品角色""" @abstractmethod def pay(self, money): pass
class AliPay(Payment): """Alipay具体产品角色""" def __init__(self, huabei=False): self.huabei = huabei
def pay(self, money): if self.huabei: print(f"使用花呗支付:¥{money}") else: print(f"使用支付宝支付:¥{money}")
class Wechat(Payment): """Wechat具体产品角色""" def pay(self, money): print(f"使用微信支付:¥{money}")
class FactoryPayment: """工厂角色""" def create_pay(self, method): if method == 'alipay': return AliPay() elif method == "wechat": return Wechat() elif method == 'huabei': return AliPay(huabei=True) else: raise TypeError(f"不支持的支付类型:{method}")
p = FactoryPayment().create_pay("huabei") p.pay(100)
|
工厂方法模式
定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类。
角色
- 抽象工厂角色(Creator)
- 具体工厂角色(Concrete Creator)
- 抽象产品角色(Product)
- 具体产品角色(Concrete Product)
优点
- 每个具体产品都对应一个具体工厂类,不需要修改工厂类代码
- 隐藏了对象创建的实现细节
缺点
每增加一个具体产品类,就必须增加一个相应的具体工厂类
示例
通过示例可以看出,该模式打破了简单工厂模式中将创建逻辑集中到一个工厂类中,继续遵循了单一职责原则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| from abc import ABCMeta, abstractmethod
class Payment(metaclass=ABCMeta): """抽象产品角色"""
@abstractmethod def pay(self, money): pass
class AliPay(Payment): """具体产品角色"""
def __init__(self, huabei=False): self.huabei = huabei
def pay(self, money): if self.huabei: print(f"使用花呗支付:¥{money}") else: print(f"使用支付宝支付:¥{money}")
class Wechat(Payment): """具体产品角色"""
def pay(self, money): print(f"使用微信支付:¥{money}")
class FactoryPayment(metaclass=ABCMeta): """抽象工厂角色"""
@abstractmethod def create_pay(self): pass
class AlipayFactoryPayment(FactoryPayment): """具体工厂角色"""
def create_pay(self): return AliPay()
class WechatFactoryPayment(FactoryPayment): """具体工厂角色"""
def create_pay(self): return Wechat()
class HuabeiFactoryPayment(FactoryPayment): """具体工厂角色"""
def create_pay(self): return AliPay(huabei=True)
p = HuabeiFactoryPayment().create_pay() p.pay(100)
|
抽象工厂模式
定义一个工厂类接口,让工厂子类来创建一系列或相关依赖的对象。
例如:生产异步手机需要处理器和操作系统两类对象进行组装,其中每类对象都有不同的种类(如处理器有骁龙、联发科、苹果;操作系统有安卓、苹果)。对于每个具体的工厂,分别生产一部手机所需要的两个对象。
相比较于工厂方法模式,抽象工厂模式的每个具体工厂都在生产一套产品
角色
- 抽象工厂角色(Creator)
- 具体工厂角色(Concrete Creator)
- 抽象产品角色(Product)
- 具体产品角色(Concrete Product)
- 客户端(Client)
优点
- 将客户端与类的具体实现相分离
- 每个工厂创建了一个完整的产品系列,使得易于交换产品系列
- 有利于产品的一致性(即产品之间的约束关系)
缺点
难以支持新种类(抽象)产品
示例
代码量提升了很多,使用起来相对复杂,特别对于添加一个新的抽象产品,比如我增加一个电池,你要增加对应的抽象电池类,具体的产品电池类,修改抽象工厂类,修改具体产品类,包括连客户端代码都要跟着对应调整。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| from abc import ABCMeta, abstractmethod
class PhoneCpu(metaclass=ABCMeta): """cpu"""
@abstractmethod def show_cpu(self): pass
class PhoneOS(metaclass=ABCMeta): """os"""
@abstractmethod def show_os(self): pass
class SnapdragonCpu(PhoneCpu): def show_cpu(self): print("骁龙处理器")
class MtkCpu(PhoneCpu): def show_cpu(self): print("联发科处理器")
class AppleCpu(PhoneCpu): def show_cpu(self): print("苹果处理器")
class AndroidOs(PhoneOS): def show_os(self): print("安卓操作系统")
class IosOs(PhoneOS): def show_os(self): print("苹果操作系统")
class Factory(metaclass=ABCMeta): @abstractmethod def make_cpu(self): pass
@abstractmethod def make_os(self): pass
class HuaweiFactory(Factory): def make_cpu(self): return MtkCpu()
def make_os(self): return AndroidOs()
class ApppleFactory(Factory): def make_cpu(self): return AppleCpu()
def make_os(self): return IosOs()
class Phone: def __init__(self, cpu, os): self.cpu = cpu self.os = os
def show(self): print("手机信息:") self.cpu.show_cpu() self.os.show_os()
def make_phone(factory): cpu = factory.make_cpu() os = factory.make_os() return Phone(cpu, os)
huawei = make_phone(HuaweiFactory()) huawei.show() print("-------------------------")
apple = make_phone(ApppleFactory()) apple.show()
|
创建者模式
将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式和抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象。
角色
- 抽象建造者(Builder)
- 具体建造者(Concrete Builder)
- 指挥者(Director)
- 产品(Product)
优点
- 隐藏了一个产品的内部结构和装配过程
- 将构造代码与标识代码分开
- 可以对构造过程进行更精细的控制
示例
代码越来越多了……,写下来感觉是对抽象工厂的进一步升级,原来的工厂(抽象和具体)改变了叫法,变成了建造者(抽象/具体),相比之前又多了一个指挥者的身份,在这里可以进构造过程进行更精细的控制,如构造顺序等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
| from abc import ABCMeta, abstractmethod
class Player: def __init__(self, hair=None, face=None, skin=None, body=None): self.hair = hair self.face = face self.skin = skin self.body = body
def show(self): print("角色参数如下:") print("发型:", self.hair) print("表情:", self.face) print("肤色:", self.skin) print("身体:", self.body)
class Hair(metaclass=ABCMeta): @abstractmethod def show_hair(self): pass
class Face(metaclass=ABCMeta): @abstractmethod def show_face(self): pass
class Skin(metaclass=ABCMeta): @abstractmethod def show_skin(self): pass
class Body(metaclass=ABCMeta): @abstractmethod def show_body(self): pass
class SortHair(Hair): def show_hair(self): return "短发"
class LongHair(Hair): def show_hair(self): return "长发"
class GrimaceFace(Face): def show_face(self): return "冷酷表情"
class PhotophobiaFace(Face): def show_face(self): return "恐怖表情"
class YellowSkin(Skin): def show_skin(self): return "黄皮肤"
class WhiteSkin(Skin): def show_skin(self): return "白皮肤"
class BlackSkin(Skin): def show_skin(self): return "黑皮肤"
class SexyBoby(Body): def show_body(self): return "性感的身材"
class StrongBoby(Body): def show_body(self): return "强壮的身材"
class PlayerBuilder(metaclass=ABCMeta): def __init__(self): self.player = Player()
@abstractmethod def build_hair(self): pass
@abstractmethod def build_face(self): pass
@abstractmethod def build_skin(self): pass
@abstractmethod def build_body(self): pass
class Humen(PlayerBuilder): """人族"""
def build_hair(self): self.player.hair = LongHair().show_hair()
def build_face(self): self.player.face = GrimaceFace().show_face()
def build_skin(self): self.player.skin = YellowSkin().show_skin()
def build_body(self): self.player.body = SexyBoby().show_body()
class Orc(PlayerBuilder): """兽族"""
def build_hair(self): self.player.hair = SortHair().show_hair()
def build_face(self): self.player.face = PhotophobiaFace().show_face()
def build_skin(self): self.player.skin = BlackSkin().show_skin()
def build_body(self): self.player.body = StrongBoby().show_body()
class PlayerDirector: def build_player(self, builder): builder.build_hair() builder.build_face() builder.build_skin() builder.build_body() return builder.player
p = PlayerDirector().build_player(Humen()) p.show()
|
![]()
开启了调试模式可以看到指挥者对构造顺序的控制
单例模式
保证一个类只有一个实例,并提供一个访问它的全局访问点
角色
优点
- 对唯一实例的受控访问
- 单例相当于全局变量,但防止了命名空间被污染
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Signton: def __new__(cls, *args, **kwargs): if not hasattr(cls, "_instance"): cls._instance = super().__new__(cls) return cls._instance
class Test(Signton): def __init__(self, a): self.a = a
aa = Test(11) bb = Test(22) print("id(aa):", id(aa)) print("id(bb):", id(bb)) print("aa.a:", aa.a) print("bb.a:", bb.a)
|
输出结果:
1 2 3 4
| id(aa): 1999229563848 id(bb): 1999229563848 aa.a: 22 bb.a: 22
|
创建型模式总结
- 抽象工厂模式和建造者模式相比于简单工厂模式和工厂方法模式而言更灵活但是也更复杂。
- 通常情况下,设计以简单工厂模式或工厂方法模式开始,当你发现设计需要更大的灵活性时,则像更复杂的设计模式演化。