Python之常用设计模式(创建型模式篇)

2021/6/20 17:24:06

本文主要是介绍Python之常用设计模式(创建型模式篇),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Python之常用设计模式

一、设计模式分类

1. 创建型模式

工厂方法模式、抽象工厂模式、建造者模式、原型模式、单例模式

2. 结构型模式

适配器模式、桥模式、组合模式、装饰模式、外观模式、享元模式、代理模式

3. 行为型模式

解释器模式、责任链模式、命令模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、访问者模式、模板方法模式

二、创建型模式

1. 简单工厂模式

  • 内容

    • 不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。
  • 角色(类)

    • 工厂角色(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) -> None:
        self.use_huabei = use_huabei

    def pay(self, money):
        if self.use_huabei:
            print(f"花呗支付{money}元")
        else:
            print(f"支付宝余额支付{money}元")


class WechatPay(Payment):
    def pay(self, money):
        print(f"微信支付{money}元")


class PaymentFactory:
    """生产支付对象的工厂类 用于生产AliPay或WechatPay对象"""
    def createPayment(self, method):
        if method == "alipay":
            return AliPay()
        elif method == "huabei":
            return AliPay(use_huabei=True)
        elif method == "wechat":
            return WechatPay()
        else:
            raise TypeError(f"No such payment named {method}")


# client
pf = PaymentFactory()
p = pf.createPayment("huabei")
p.pay(100)

上面例子中,工厂角色(类)是PaymentFactory,抽象产品角色是Payment,具体产品角色是AliPay和WechatPay。

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

2. 工厂方法模式

  • 内容

定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类。

  • 角色
    • 抽象工厂角色(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) -> None:
        self.use_huabei = use_huabei

    def pay(self, money):
        if self.use_huabei:
            print(f"花呗支付{money}元")
        else:
            print(f"支付宝余额支付{money}元")


class WechatPay(Payment):
    def pay(self, money):
        print(f"微信支付{money}元")


class BankPay(Payment):
    def pay(self, money):
        print(f"银联支付{money}元")


class PaymentFactory(metaclass=ABCMeta):
    @abstractmethod
    def createPayment(self):
        pass


class AliPayFactory(PaymentFactory):
    def createPayment(self):
        return AliPay()


class WechatPayFactory(PaymentFactory):
    def createPayment(self):
        return WechatPay()


class HuaBeiFactory(PaymentFactory):
    def createPayment(self):
        return AliPay(use_huabei=True)


class BankPayFactory(PaymentFactory):
    def createPayment(self):
        return BankPay()


# client
pf = HuaBeiFactory()
p = pf.createPayment()
p.pay(100)

上面例子中,抽象工厂角色是PaymentFactory,具体工厂角色是AliPayFactory、WechatPayFactory、HuaBeiFactory和BankPayFactory,抽象产品角色是Payment,具体产品角色是AliPay、WechatPay、BankPay。

  • 优点
    • 每个具体产品都对应一个具体工厂类,不需要修改工厂类代码
    • 隐藏了对象创建的实现细节
  • 缺点
    • 每增加一个具体产品类,就必须增加一个相应的具体工厂类

3. 抽象工厂模式

  • 内容

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

  • 角色
    • 抽象工厂角色(Creator)
    • 具体工厂角色(Concrete Creator)
    • 抽象产品角色(Product)
    • 具体产品角色(Concrete Product)
    • 客户端(Client)
from abc import abstractmethod, ABCMeta


# 抽象产品
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 MediaTekCPU(CPU):
    def show_cpu(self):
        print("联发科CPU")


class SnapDragonCPU(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 BigShell()

    def make_cpu(self):
        return SnapDragonCPU()

    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, cpu, os, shell) -> None:
        self.cpu = cpu
        self.os = os
        self.shell = shell

    def show_info(self):
        print("手机信息:")
        self.cpu.show_cpu()
        self.os.show_os()
        self.shell.show_shell()


def make_phone(factory):
    cpu = factory.make_cpu()
    os = factory.make_os()
    shell = factory.make_shell()
    return Phone(cpu, os, shell)


p1 = make_phone(MiFactory())
p1.show_info()

  • 优点
    • 将客户端与类的具体实现相分离
    • 每个工厂创建了一个完整的产品系列,使得易于交换产品系列
    • 有利于产品的一致性(即产品之间的约束关系)
  • 缺点
    • 难以支持新种类的(抽象)产品

4. 建造者模式

  • 内容

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

  • 角色
    • 抽象建造者(Builder)
    • 具体建造者(Concrete Builder)
    • 指挥者(Director)
    • 产品(Product)
from abc import abstractmethod, ABCMeta


class Player():
    """产品"""
    def __init__(self, face=None, body=None, arm=None, leg=None) -> None:
        self.face = face
        self.body = body
        self.arm = arm
        self.leg = leg

    def __str__(self) -> str:
        return f"{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) -> None:
        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) -> None:
        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 builder_player(self, builder):
        builder.build_body()
        builder.build_face()
        builder.build_arm()
        builder.build_leg()
        return builder.player


# client
builder = SexyGirlBuilder()
director = PlayerDirector()
p = director.builder_player(builder)
print(p)

建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象。

  • 优点
    • 隐藏了一个产品的内部结构和装配过程
    • 将构造代码与表示代码分开
    • 可以对构造过程进行更精细的控制

5. 单例模式

  • 内容

保证一个类只有一个实例,并提供一个访问它的全局访问点。

  • 角色
    单例(Singleton)
from abc import abstractmethod, ABCMeta


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) -> None:
        self.a = a


a = MyClass(10)
b = MyClass(20)
print(a.a)  # 20
print(b.a)  # 20

  • 优点
    • 对唯一实例的受控访问
    • 单例相当于全局变量,但防止了命名空间被污染

6. 创建型模式总结

  1. 抽象工厂模式和建造者模式相比于简单工厂模式和工厂方法模式而言更灵活也更复杂。
  2. 通常情况下、设计以简单工厂模式或工厂方法模式开始,当你发现设计需要更大的灵活性时,则像更复杂的设计模式演化。


这篇关于Python之常用设计模式(创建型模式篇)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程