Github仓库地址
概述
23中设计模型分为常见的三大类:创建型模式、结构型模式和行为型模式
创建型模式
简单工厂模式
描述
简单工厂模式不是23中设计模式中的。简单工厂模式不直接向客户端暴露对象创建的细节,而是通过一个工厂类来负责创建产品类的实例
角色
- 抽象产品角色:给具体产品角色提供接口规范
- 具体产品角色:实现同类内容的不同实现结果
- 工厂角色:负责传入不同的参数,调用不同的具体产品角色,实现不同的功能
实现
from abc import ABCMeta, abstractmethod
# 抽象产品角色:给具体产品角色提供统一的接口规范
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
pass
# 具体产品角色
class Alipay(Payment):
def __init__(self, use_huabei=False):
self.use_huabei = use_huabei
def pay(self, money):
if self.use_huabei == True:
print("花呗支付了{0}元!".format(money))
else:
print("支付宝余额支付了{0}元!".format(money))
class WechatPay(Payment):
def pay(self, money):
print("微信支付了%d元!" % (money))
# 工厂类角色
class PaymentFactory:
def create_payment(self, method):
if method == 'Alipay':
return Alipay()
elif method == 'WechatPay':
return WechatPay()
elif method == 'HuabeiPay':
return Alipay(use_huabei=True)
else:
raise TypeError('No such payment named %s' % method)
优点
- 隐藏了对象(具体产品角色)创建的细节
- 面对新的具体产品对象,客户端(上层)不需要修改代码,仅在参数传递上有所改动
缺点
- 违反了单一职责原则:工厂类对象中包含了多种具体产品角色的选择逻辑
- 违反了开放封闭原则:当新增具体产品角色时,需要对工厂类对象进行修改
工厂方法模式
描述
在简单工厂模式的基础上,定义一个抽象工厂和具体工厂的角色,从而让客户端决定具体实例化哪一个产品
角色
- 抽象产品角色:给具体产品角色的创建提供接口规范
- 具体产品角色:创建不同的产品
- 抽象工厂角色:给具体产品角色的调用提供接口规范
- 具体工厂角色:创建不同的工厂
实现
from abc import ABCMeta, abstractmethod
# 抽象产品角色:给具体产品角色提供统一的接口规范
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
pass
# 具体产品角色
class Alipay(Payment):
def __init__(self, use_huabei=False):
self.use_huabei = use_huabei
def pay(self, money):
if self.use_huabei == True:
print("花呗支付了{0}元!".format(money))
else:
print("支付宝余额支付了{0}元!".format(money))
class WechatPay(Payment):
def pay(self, money):
print("微信支付了%d元!" % (money))
# 抽象工厂角色
class PaymentFactory(metaclass=ABCMeta):
@abstractmethod
def create_payment(self):
pass
# 具体工厂角色
class AlipayFactory(PaymentFactory):
def create_payment(self):
return Alipay()
class WechatPayFactory(PaymentFactory):
def create_payment(self):
return Alipay()
class HuabeiFactory(PaymentFactory):
def create_payment(self):
return Alipay(use_huabei=True)
# 客户端调用
hfp = HuabeiFactory().create_payment()
hfp.pay(100)
优点
- 每个具体产品一一对应一个具体工厂类,不需要修改具体工厂类代码
- 隐藏具体产品对象创建的实现细节
缺点
- 每增加一个具体产品类,需要增加一个相应的具体工厂类
抽象工厂模式
描述
在工厂模式的基础上又进行了一层抽象提取
角色
- 抽象产品角色:给具体产品角色的创建提供接口规范
- 具体产品角色:创建不同的产品
- 抽象工厂角色:给具体产品角色的调用提供接口规范
- 具体工厂角色:创建不同的工厂
- 客户端
实现
from abc import ABCMeta, abstractmethod
# 抽象产品角色
class PhoneShell(metaclass=ABCMeta):
@abstractmethod
def show_shell(self):
pass
class PhoneCPU(metaclass=ABCMeta):
@abstractmethod
def show_cpu(self):
pass
class PhoneOS(metaclass=ABCMeta):
@abstractmethod
def show_os(self):
pass
# 具体产品角色
class SmallShell(PhoneShell):
def show_shell(self):
print('普通手机小手机壳')
class BigShell(PhoneShell):
def show_shell(self):
print('普通手机大手机壳')
class AppleShell(PhoneShell):
def show_shell(self):
print('苹果手机壳')
class SnapDragonCPU(PhoneCPU):
def show_cpu(self):
print('骁龙CPU')
class HuaweiCPU(PhoneCPU):
def show_cpu(self):
print('化为CPU')
class AppleCPU(PhoneCPU):
def show_cpu(self):
print('苹果CPU')
class AndroidOS(PhoneOS):
def show_os(self):
print('IOS系统')
class AppleOS(PhoneOS):
def show_os(self):
print('安卓系统')
# 抽象工厂角色
class PhoneFactory(metaclass=ABCMeta):
@abstractmethod
def make_shell(self):
pass
@abstractmethod
def make_cpu(self):
pass
@abstractmethod
def make_os(self):
pass
# 具体工厂角色
class HuaweiFactory(PhoneFactory):
def make_shell(self):
return SmallShell()
def make_cpu(self):
return HuaweiCPU()
def make_os(self):
return AndroidOS()
# 对具体工厂的实现加以限制,避免随意使用:苹果手机只能用苹果的CPU
class AppleFactory(PhoneFactory):
def make_shell(self):
return AppleShell()
def make_cpu(self):
return AppleCPU()
def make_os(self):
return AppleOS()
# 客户端
class Phone:
def __init__(self, shell, cpu, os):
self.shell = shell
self.cpu = cpu
self.os = os
def show_info(self):
print('手机信息:')
self.shell.show_shell()
self.cpu.show_cpu()
self.os.show_os()
def make_phone(factory):
shell = factory.make_shell()
cpu = factory.make_cpu()
os = factory.make_os()
return Phone(shell, cpu, os)
# 用户端调用
p = make_phone(HuaweiFactory())
p.show_info()
优点
- 客户端与类的具体实现相分离
- 每个工厂都能创建一个完整的产品系列
- 产品之间存在约束关系:有利于产品的一致性
缺点
- 难以支持新种类的(抽象)产品:例如要增加内存版本的生产信息(抽象产品需要新增),则所有的工厂都需要修改(抽象工厂需要修改)
建造者模式
描述
将一个复杂对象的构建与他的表示分离,是的同样的构建过程可以创建不同的表示
角色
- 产品
- 抽象创建者
- 具体创建者
- 指挥者
实现
from abc import ABCMeta, abstractmethod
# 产品
class Player_Product:
def __init__(self, face=None, body=None, arms=None, legs=None):
self.face = face
self.body = body
self.arms = arms
self.legs = legs
def __str__(self):
return '%s,%s,%s,%s' % (self.face, self.body, self.arms, self.legs)
# 抽象建造者
class PlayerBuilder(metaclass=ABCMeta):
@abstractmethod
def build_face(self):
pass
@abstractmethod
def build_body(self):
pass
@abstractmethod
def build_arms(self):
pass
@abstractmethod
def build_legs(self):
pass
# 具体建造者,隐藏了一个产品的内部结构
class GirlBuilder(PlayerBuilder):
def __init__(self):
self.player = Player_Product()
def build_face(self):
self.player.face = '漂亮的脸蛋'
def build_body(self):
self.player.body = '苗条的身材'
def build_arms(self):
self.player.arms = '细细的胳膊'
def build_legs(self):
self.player.legs = '大长腿'
class MonsterBuilder(PlayerBuilder):
def __init__(self):
self.player = Player_Product()
def build_face(self):
self.player.face = '绿脸'
def build_body(self):
self.player.body = '魁梧的身体'
def build_arms(self):
self.player.arms = '粗壮的胳膊'
def build_legs(self):
self.player.legs = '粗壮的大腿'
# 指挥者,构造代码(构造代码和表示代码分开),可以对构造过程进行更加精细地控制
class PlayerDirectory():
def builder_player(self, builder):
"""
隐藏了装配过程
:param builder:
:return:
"""
builder.build_face()
builder.build_body()
builder.build_arms()
builder.build_legs()
return builder.player
# 用户端调用
builder = GirlBuilder()
director = PlayerDirectory()
p = director.builder_player(builder)
print(p)
优点
- 具体建造者之间独立,容易扩展
- 便于控制细节风险
缺点
- 产品需要有共同点,这些共同点通过不同的组合可以组合出不同的产品
- 如果这些共同点可以组成极多的产品,则会有很多的产品建造者
抽象工厂 VS 建造者模式
- 前者注重整体:每一个具体工厂都能制造一个产品:华为手机工厂、苹果手机工厂、锤子手机工厂
- 后者注重局部:产线就一个(指挥者),根据搭配(具体建造者)制造不同的产品:用ardroid、麒麟、小手机壳,就生产华为手机;用ios、M2、大手机壳,就生产苹果手机
理解
https://zhuanlan.zhihu.com/p/405399335
这个描述绝了
抽象工厂模式像是从某宝输入“电脑”的关键字直接进行购买,获得一个已经完整的电脑。
创建者模式,更像是“找个一个电脑的外壳,往该外壳内一步一步的组装零件,最后得到一个完整的电脑”。
单例模式
描述
保证一个类只有一个实例,并提供一个访问它的全局访问点
角色
- 单例
实现
class Singleton:
def __new__(cls, *args, **kwargs):
# 如果没有实例,赋予一个实例
if not hasattr(cls, "_instance"):
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
class MyClass(Singleton):
def __init__(self, a):
self.a = a
# 用户端调用
ms1 = MyClass(1)
ms2 = MyClass(2)
print(ms1.a, ms2.a)
print(id(ms1), id(ms2))
优点
- 对唯一实例的受控访问
- 单例相当于全局变量,防止了命名空间被污染
结构型模式
适配器模式
描述
将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
角色
- 目标接口
- 待适配的类
- 适配器
实现1:多继承
from abc import ABCMeta, abstractmethod
# 目标接口:抽象方法
class Payment(object, metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
pass
# 目标接口:具体实现
class Alipay(Payment):
def pay(self, money):
print('支付了%d' % money)
# 待适配的类
class BankPay():
def cost(self, money):
print('银联支付了%d' % money)
# 类适配器
class PaymentAdapter(Payment, BankPay):
"""
把不兼容cost转换成pay
"""
def pay(self, money):
self.cost(money)
# 客户端调用
p = PaymentAdapter()
p.pay(100)
优点
- 想使用一个已经存在地类,而它的接口不符合要求
- 适用于单个对象需要适配的场景:多继承的适配方式,一个类适配器只能适配一个待适配的类
实现2:组合
from abc import ABCMeta, abstractmethod
# 目标接口:抽象方法
class Payment(object, metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
pass
# 目标接口:具体实现
class Alipay(Payment):
def pay(self, money):
print('支付了%d' % money)
# 待适配的类
class BankPay():
def cost(self, money):
print('银联支付了%d' % money)
# 待适配的类
class ApplePay():
def cost(self, money):
print('苹果支付了%d' % money)
# 对象适配器
class PaymentAdapter(Payment):
def __init__(self, payment):
self.payment = payment
def pay(self, money):
self.payment.cost(money)
# 客户端调用
p = PaymentAdapter(ApplePay())
p.pay(100)
p = PaymentAdapter(BankPay())
p.pay(100)
优点
- 想使用多个已经存在地类,而他们的接口不符合要求,但他们的接口都一致
- 适用于多个对象需要适配的场景:组合的适配方式,一个类适配器可以适配多个接口一致的待适配的类
桥模式
有难度,暂时跳过
https://blog.csdn.net/hbuxiaofei/article/details/106888178