python创建型模式

工厂模式

Posted by QQL on January 18, 2019

创建型模式

创建对象时用到的模式

简单工厂模式(给工厂模式铺垫)

用来生产对象的工厂

from abc import ABCMeta, abstractmethod


class Payment(metaclass=ABCMeta):
    # abstract class
    @abstractmethod
    def pay(self, money):
        pass

class Alipay(Payment):
    def __init__(self, use_huabei=False):
        self.use_huaei = use_huabei

    def pay(self, money):
        if self.use_huaei:
            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)



# client
# 高层代码不需要知道Alipay/Wechatpay有什么代码,只需在create_payment()传入要调用的类
pf = PaymentFactory()
p = pf.create_payment('huabei')
p.pay(100)

优点

隐藏了对象创建的实现细节 客户端不需要修改代码

缺点

违反了单一职责原则,将创建逻辑集中到一个工厂类(各种实例都在一个工厂内)里 当添加新产品时,需要修改工厂类代码,违反了开闭原则

工厂方法模式(常用)

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

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


class Payment(metaclass=ABCMeta):
    # abstract class
    @abstractmethod
    def pay(self, money):
        pass


class Alipay(Payment):
    def __init__(self, use_huabei=False):
        self.use_huaei = use_huabei

    def pay(self, money):
        if self.use_huaei:
            print("花呗支付%d元." % money)
        else:
            print("支付宝余额支付%d元." % money)


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


class BankPay(Payment):
    """
    创建新的功能BankPay,无需修改原有代码
    """
    def pay(self, money):
        print("银行卡支付%d元." % money)


class PaymentFactory(metaclass=ABCMeta):
    """
    抽象工厂角色(Creator)
    """
    @abstractmethod
    def create_payment(self):
        pass


class AlipayFactory(PaymentFactory):
    """
    具体工厂角色(Concrete Creator)
    """
    def create_payment(self):
        return Alipay()


class WechatPayFactory(PaymentFactory):
    """
    具体工厂角色(Concrete Creator)
    """
    def create_payment(self):
        return WechatPay()


class HuabeiFactory(PaymentFactory):
    """
    具体工厂角色(Concrete Creator)
    """
    def create_payment(self):
        return Alipay(use_huabei=True)


class BankPayFactory(PaymentFactory):
    """
    具体工厂角色(Concrete Creator)
    创建新的功能,只需创建新的工厂,无需修改原代码,就达到添加新功能的效果
    """
    def create_payment(self):
        return BankPay()


# client
# 增加新的功能不改变原功能的使用
pf = HuabeiFactory()
p = pf.create_payment()
p.pay(100)

优点

每个具体产品都对应一个具体工厂类,不需要修改工厂类代码 隐藏了对象创建的实现细节

缺点

每增加一个具体产品类,就必须增加一个相应的具体工厂类

抽象工厂模式(用的比较少)

内容:定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象

:生产一部手机,需要手机壳、CPU、操作系统三类对象进行组装,其中每类对象都有不同的种类。对每个具体工厂,分别生产一部手机所需要的三个对象。

相比工厂方法模式,抽象工厂模式中的每个具体工厂都生产一套产品。

角色

  • 抽象工厂角色(Creator)
  • 具体工厂角色(Concrete Creator)
  • 抽象产品角色(Product)
  • 具体产品角色(Concrete Product)
  • 客户端(Client)
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/12/1

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 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_cpu(self):
        return SnapDragonCPU()

    def make_os(self):
        return Android()

    def make_shell(self):
        return BigShell()


class HuaweiFactory(PhoneFactory):
    def make_cpu(self):
        return MediaTekCPU()

    def make_os(self):
        return Android()

    def make_shell(self):
        return SmallShell()


class IPhoneFactory(PhoneFactory):
    def make_cpu(self):
        return AppleCPU()

    def make_os(self):
        return IOS()

    def make_shell(self):
        return AppleShell()


# ------客户端------


class Phone:
    def __init__(self, cpu, os, shell):
        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/os/shell)组成的对象Phone
	"""
    cpu = factory.make_cpu()
    os = factory.make_os()
    shell = factory.make_shell()
    return Phone(cpu, os, shell)


p1 = make_phone(IPhoneFactory())  # 只需传入不同的工厂
p1.show_info()

优点

将客户端与类的具体实现相分离 每个工厂创建了一个完整的产品系列,使得易于交换产品系列 有利于产品的一致性(即产品之间的约束关系)

缺点

难以支持新种类的(抽象)产品

建造者模式

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

  • 抽象建造者(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 Monster(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_body()
        builder.build_face()
        builder.build_arm()
        builder.build_leg()
        return builder.player


# client

builder = Monster()
director = PlayerDirector()
p = director.build_player(builder)
print(p)

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

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

单例模式

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

  • 单例(Singleton)
class Singleton:
    def __new__(cls, *args, **kwargs):  # __new__控制实例化的对象
        if not hasattr(cls, "_instance"):  # 第一次实例化会生成_instance
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance  # 第二次实例化时就直接返回之前实例化的对象,而不重新生成对象


class MyClass(Singleton):
    def __init__(self, a):
        self.a = a  # 相当于维护了同一个a,减少资源浪费


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

print(a.a)  # 20
print(b.a)  # 20
print(id(a), id(b))  # id相同

优点
对唯一实例的受控访问
单例相当于全局变量,但防止了命名空间被污染(全局变量占了一个变量名,单例可以随时换)

创建型模式小结

抽象工厂模式和建造者模式相比于简单工厂模式和工厂方法模式而言更灵活也更复杂。

通常情况下、设计以简单工厂模式或工厂方法模式开始,当你发现设计需要更大的灵活性时,则像更复杂的设计模式演化。