Python设计模式——创建型模式

简单工厂模式

  • 内容:不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例
  • 角色:
    • 工厂角色(Creator)
    • 抽象产品角色(Product)
    • 具体产品角色(Concrete Product)
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:
            print("花呗支付%d元." % money)
        else:
            print("支付宝余额支付%d元." % 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 == 'wechat':
            return WechatPay()
        elif method == 'huabei':
            return Alipay(use_huabei=True)
        else:
            raise TypeError('No such payment named %s' % method)

# 客户端
pf = PaymentFactory()
p = pf.create_payment('huabei')
p.pay(100)
花呗支付100元.

使用工厂类进行包装,使得客户端无需了解内部调用的更多细节

  • 优点:
    • 隐藏了对象创建的实现细节
    • 客户端不需要修改代码
  • 缺点:
    • 违反了单一职责原则,将创建逻辑集中到一个工厂类里
    • 当添加新产品时,需要修改工厂类代码,违反了开闭原则

工厂方法模式

  • 内容:定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类。
  • 角色
    • 抽象工厂角色(Creator)
    • 具体工厂角色(Concrete Creator)
    • 抽象产品角色(Product)
    • 具体产品角色(Concrete Product)
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:
            print("花呗支付%d元." % money)
        else:
            print("支付宝余额支付%d元." % money)

class WechatPay(Payment):
    def pay(self, money):
        print("微信支付%d元." % money)

class BankPay(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 WechatPay()
    
class HuabeiFactory(PaymentFactory):
    def create_payment(self):
        return Alipay(use_huabei=True)
    
class BankPayFactory(PaymentFactory):
    def create_payment(self):
        return BankPay()
    

pf = HuabeiFactory()
p = pf.create_payment()
p.pay(100)
花呗支付100元.
  • 优点:
    • 每个具体产品都对应一个具体工厂类,不需要修改工厂类代码
    • 隐藏了对象创建的实现细节
  • 缺点:
    • 多每增加一个具体产品类,就必须增加一个相应的具体工厂类

抽象工厂模式

  • 内容:定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象。
  • 例:生产一部手机,需要手机壳、CPU、操作系统三类对象进行组装其中每类对象都有不同的种类。对每个具体工厂,分别生产一部手机所需要的三个对象。
  • 相比工厂方法模式,抽象工厂模式中的每个具体工厂都生产一套产品。
from abc import ABCMeta, abstractmethod


# 抽象产品
class PhoneShell(metaclass=ABCMeta):
    @abstractmethod
    def show_shell(self):
        pass

class CPU(metaclass=ABCMeta):
    @abstractmethod
    def show_cpu(self):
        pass

class OS(metaclass=ABCMeta):
    @abstractmethod
    def show_os(self):
        pass


# 抽象工厂
class PhoneFactory(metaclass=ABCMeta):
    @abstractmethod
    def make_shell(self):
        pass
    
    @abstractmethod
    def make_cpu(self):
        pass
    
    @abstractmethod
    def make_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(CPU):
    def show_cpu(self):
        print("骁龙CPU")

class MediaTekCPU(CPU):
    def show_cpu(self):
        print("联发科CPU")

class AppleCPU(CPU):
    def show_cpu(self):
        print("苹果CPU")

class Android(OS):
    def show_os(self):
        print("Android系统")

class IOS(OS):
    def show_os(self):
        print("iOS系统")


# 具体工厂
class MiFactory(PhoneFactory):
    def make_shell(self):
        return SmallShell()
    
    def make_cpu(self):
        return SnapDragonCPU()
    
    def make_os(self):
        return Android()
    
class HuaweiFactory(PhoneFactory):
    def make_shell(self):
        return BigShell()
    
    def make_cpu(self):
        return MediaTekCPU()
    
    def make_os(self):
        return Android()

class IPhoneFactory(PhoneFactory):
    def make_shell(self):
        return AppleShell()
    
    def make_cpu(self):
        return AppleCPU()
    
    def make_os(self):
        return IOS()
    

# 客户端
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)

p1 = make_phone(IPhoneFactory())
p1.show_info()
手机信息:
苹果手机壳
苹果CPU
iOS系统
  • 优点:
    • 将客户端与类的具体实现相分离
    • 每个工厂创建了一个完整的产品系列,使得易于交换产品系列
    • 有利于产品的一致性(即产品之间的约束关系)
  • 缺点:
    • 难以支持新种类的(抽象)产品

建造者模式

  • 内容:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
  • 角色
    • 抽象建造者(Builder)
    • 具体建造者(Concrete Builder)
    • 指挥者(Director)
    • 产品(Product)
from abc import ABCMeta, abstractmethod

class Player:
    def __init__(self, face=None, body=None, arm=None, leg=None):
        self.face = face
        self.body = body
        self.arm = arm
        self.leg = leg

    def __str__(self):
        return "%s, %s, %s, %s" % (self.face, self.body, self.arm, self.leg)
    

class PlayerBuilder(metaclass=ABCMeta):
    @abstractmethod
    def build_face(self):
        pass
    
    @abstractmethod
    def build_body(self):
        pass
    
    @abstractmethod
    def build_arm(self):
        pass
    
    @abstractmethod
    def build_leg(self):
        pass
    

class SexyGirlBuilder(PlayerBuilder):
    def __init__(self):
        self.player = Player()
        
    def build_face(self):
        self.player.face = "漂亮脸蛋"
        
    def build_body(self):
        self.player.body = "苗条身材"
        
    def build_arm(self):
        self.player.arm = "细长手臂"
        
    def build_leg(self):
        self.player.leg = "大长腿"
        

class MonsterBuilder(PlayerBuilder):
    def __init__(self):
        self.player = Player()
        
    def build_face(self):
        self.player.face = "丑陋脸蛋"
        
    def build_body(self):
        self.player.body = "胖子身材"
        
    def build_arm(self):
        self.player.arm = "粗短手臂"
        
    def build_leg(self):
        self.player.leg = "短粗腿"


class PlayerDirector: # 控制组装顺序
    def build_player(self, builder):
        builder.build_face()
        builder.build_body()
        builder.build_arm()
        builder.build_leg()
        return builder.player
    

# 客户端
builder = SexyGirlBuilder()
director = PlayerDirector()
p = director.build_player(builder)
print(p) # 调用__str__方法
漂亮脸蛋, 苗条身材, 细长手臂, 大长腿
  • 建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象。
  • 优点:
    • 隐藏了一个产品的内部结构和装配过程
    • 将构造代码与表示代码分开
    • 可以对构造过程进行更精细的控制

单例模式

  • 内容:保证一个类只有一个实例,并提供一个访问它的全局访问点。
  • 角色:
    • 单例(Singleton)
  • 优点:
    • 对唯一实例的受控访问
    • 单例相当于全局变量,但防止了命名空间被污染

补充__new__函数介绍:

面向对象的编程语言,类的实例化都一定包含两个步骤: (1)在内存中创建对象,即开辟一块内存空间来存放类的实例(Instance); (2)初始化对象,即给实例的属性赋予初始值,例如全部填 0;

在 python 中,第一步由__new__函数负责,第二步由__init__函数负责。

class Singleton:
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            cls._instance = super().__new__(cls)
        return cls._instance
    

class MyClass(Singleton):
    def __init__(self, s):
        self.s = s


a = MyClass(10)
b = MyClass(20)

print(a.s)
print(b.s)
print(id(a), id(b))
20
20
1506330511680 1506330511680
  • 运行机制:确保类有且仅有一个特定类型的对象,并提供全局访问点
  • 应用场景:程序运行过程中只生成一个实例(避免对同一资源产生相互冲突的请求),如日志记录、数据库操作
  • 意图:
    • 确保类只有一个对象被创建
    • 为对象提供一个访问点,以使程序可以全局访问该对象
    • 控制共享资源的并行访问
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值