知识储备:
1.接口:若干抽象方法的集合
作用:限制实现接口的类必须按照接口给定的调用方式实现这些方法;对高层模块隐藏了类的内部实现。
2.面向对象设计SOLID原则
- 开放封闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
- 里氏替换原则:所有引用父类的地方必须能透明的使用其子类的对象。
- 依赖倒置原则:高层模块不应该依赖底层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程。
- 接口隔离原则:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
- 单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责某一项职责。
3.设计模式分类
创建型模式(5种):工厂方法模式、抽象工厂模式、创建者模式、原型模式、单例模式
结构型模式(7种):适配器模式、桥模式、组合模式、装饰模式、外观模式、享元模式、代理模式
行为型模式(11种):解释器模式、责任链模式、命令模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、访问者模式、模板方法模式
1、简单工厂模式
内容:不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。
角色:
- 工厂角色(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_hubei = use_huabei def pay(self, money): if self.use_hubei: print("花呗支付%d元" % money) else: print("支付宝余额支付%d" % money) class Wechat(Payment): def pay(self, money): print("微信支付%d元" % money) # 工厂类 class PaymentFactory: def create_payment(self, method): if method == 'alipay': return Alipay() elif method == 'wechat': return Wechat() elif method == 'huabei': return Alipay(use_huabei=True) else: raise TypeError("No such payment named %s" % method) # client pf = PaymentFactory() p = pf.create_payment('huabei') p.pay(100) ## 工厂角色: PaymentFactory 抽象产品角色:Payment 具体产品角色:Alipay,WechatPay
优点:
1.隐藏了对象创建的实现细节
2.客户端不需要修改代码
缺点:
1.违反了单一职责原则,将创建逻辑集中到一个工厂类里
2.当添加新产品时,需要修改工厂类代码,违反了开闭原则
2、工厂方法模式
内容:定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类。
角色:
- 抽象工厂角色(Creator)
- 具体工厂角色(Concrete Cretor)
- 抽象产品角色(Product)
- 具体产品角色(Concrete Product)
from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta): @abstractmethod def pay(self, money): pass class PaymentFactory(metaclass=ABCMeta): @abstractmethod def create_payment(self): 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 Wechat(Payment): def pay(self, money): print("微信支付%d元" %money) class AlipayFactory(PaymentFactory): def create_payment(self): return Alipay() class WechatPayFactory(PaymentFactory): def create_payment(self): return Wechat() # client pf = AlipayFactory() p = pf.create_payment() p.pay(100) ## 抽象工厂角色:PaymentFactory 具体工厂角色:AliFactory,WechatFactory 抽象产品角色:Payment 具体产品角色:AliPay,WechatPay
优点:
1.每个产品都对应一个具体工厂类,不需要修改修改共产类代码
2.隐藏了对象创建的实现细节
缺点:
1.每增加一个具体产品类,就必须增加一个相应的具体工厂类
3、抽象工厂模式
内容:定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象。
例:生产一部手机,需要手机壳、CPU、操作系统三类对象进行组装,其中每类都有不同的种类。对每个具体工厂,分别生产一部手机所需要的三个对象。
相比工厂方法模式,抽象工厂模式中的每个具体工厂都生产一套产品。
角色:
- 抽象工厂角色(Creator)
- 具体工厂角色(Concrete Cretor)
- 抽象产品角色(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 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 = factory.make_cpu() os = factory.make_os() shell = factory.make_shell() return Phone(cpu, os, shell) p1 = make_phone(IPhoneFactory()) p1.show_info()
优点:
1.将客户端与类的具体实现相分离
2.每个工厂创建了一个完整的产品系列,使得易于交换产品系列
3.有利于产品一致性(即产品之间的约束关系)
缺点:
1.难以支持新种类的(抽象)产品
4、创建者模式
内容:将一个复杂对象的构造与它的表示分离,使得同样的构建过程可以创建不同的表示。
角色:
- 抽象建造者(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) ## 抽象建造者:PlayerBuilder 具体建造者:SexyGirlBuilder, Monster 指挥者:PlayerDirector 产品:p
建造者模式与抽象工厂模式类似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象。
优点:
1.隐藏了一个产品的内部结构和装配过程
2.将构造代码与表示代码分开
3.可以对构造过程更精细的控制
5、单例模式
内容:保证一个类只有一个实例,并提供一个访问它的全局访问点
角色:
- 单例
优点:
1.对唯一实例的受控访问
2.单例相当于全局变量,但防止了命名空间被污染。
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 a = Myclass(10) b = Myclass(20) print(a.a) print(b.a) print(id(a), id(b))
## 创建型模式小结 1、抽象工厂模式和建造者模式相比于简单工厂模式和工厂方法模式而言更灵活也更复杂。 2、通常情况下,设计以简单工厂模式或工厂方法模式开始,当你发现设计需要更大的灵活性时,则像更复杂的设计模式演化。