参考博客:https://www.cnblogs.com/alex3714/articles/5760582.html
一、设计模式介绍
1.设计模式分类
23种设计模式,分类三类:
创建型、结构性、行为型。
2.设计模式的六大原则
1)开闭原则(Open Close Principle)
开闭原则是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。
2)里氏代换原则(Liskov Substitution Principle,LSP)
里氏代换原则是面向对象设计的基本原则之一。任何基类可以出现的地方,子类一定可以出现。LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
理解:里氏代换即某个基类的子类,放到基类所处的位置,不会影响软件的运行。简单的理解为一个软件实体如果使用的是一个父类,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。也就是说,软件里面,把父类都替换成它的子类,程序的行为没有变化。所以我们认为,基类中的所有方法应该是所有子类所共有的方法,而不应该出现需要子类重写的方法。这样才能使用子类替代基类。在设计的时候,尽量从抽象类继承,而不是从具体类。
参考博客:https://blog.csdn.net/king123456man/article/details/81626110
3)依赖倒转原则(Dependence Inversion Principle,DIP)
主要包含以下三层含义:
- 高层模块不应该依赖低层模块,两者都应该依赖其抽象
- 抽象不应该依赖细节
- 细节应该依赖抽象
参考博客:https://blog.csdn.net/king123456man/article/details/81626127
4)接口隔离原则(Interface Segregation Principle,ISP)
其实通俗来理解就是,不要在一个接口里面放很多的方法,这样会显得这个类很臃肿不堪。接口应该尽量细化,一个接口对应一个功能模块,同时接口里面的方法应该尽可能的少,使接口更加轻便灵活。
参考博客:https://blog.csdn.net/king123456man/article/details/81626059
5)迪米特法则(最少知道原则)(Demeter Principle)
一个实体应该尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6)合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。
参考博客:https://blog.csdn.net/u012361379/article/details/88605867
二、创建型设计模式
对象的创建会消耗系统的很多资源,所以单独对对象的创建进行研究,从而能够高效地创建对象就是创建型模式要探讨的问题。这里有6个具体的创建型模式可供研究,分别是:
- 简单工厂模式(Simple Factory)
- 工厂方法模式(Factory Method)
- 抽象工厂模式(Abstract Factory)
- 创建者模式(Builder)
- 原型模式(Prototype)
- 单例模式(Singleton)
严格来说,简单工厂模式不是23个设计模式之一。
1.简单工厂模式
最简单的设计模式。
######### 简单工厂设计模式 ########## # 形状抽象类 class Shape(object): def draw(self): raise NotImplementedError # 圆形类 class Circle(Shape): def draw(self): print('画圆形') # 四边形类 class Rectangle(Shape): def draw(self): print('画四边形') # 简单工厂类 class ShapeFactory(object): def create(self, shape): if shape == 'Circle': return Circle() elif shape == 'Rectangle': return Rectangle() else: return None if __name__ == '__main__': # 创建一个简单工厂实例 fac = ShapeFactory() # 使用工厂实例创建Circle对象 obj = fac.create('Circle') # 调用对象中的draw方法 obj.draw()
用一个简单的工厂类,来统一的提供给用户调用,根据用户提供的信息返回创建的实例。
2.工厂方法模式
在简单工厂模式中,我们只有一个工厂类,其中通过if else来判断需要创建什么对象,然后返回。
但我们想添加一个形状时,除了要实现相应的形状子类以外,还要修改这个唯一的工厂类。在if else判断语句中加一个分支。
此时,我们就可以将工厂类也抽象出一个基类,并为每个形状都创建一个工厂子类。
UML图如下所示:
######### 工厂方法设计模式 ########## # 形状基类,所有形状子类继承于该类 class Shape(object): '''形状工厂类''' def getShape(self): return self.shape_name def draw(self): raise NotImplementedError # 圆形类 class Circle(Shape): def __init__(self): self.shape_name = "Circle" def draw(self): print('draw circle') # 四边形类 class Rectangle(Shape): def __init__(self): self.shape_name = "Retangle" def draw(self): print('draw Rectangle') # 形状工厂的基类 class ShapeFactory(object): '''接口基类''' def create(self): '''把要创建的工厂对象装配进来''' raise NotImplementedError # 圆形工厂类 class CircleFactory(ShapeFactory): def create(self): return Circle() # 四边形工厂类 class RectangleFactory(ShapeFactory): def create(self): return Rectangle() # 创建一个圆形工厂实例 cf = CircleFactory() # 使用圆形工厂产生圆形对象 obj = cf.create() # 调用圆形对象的shape_name obj.getShape() # 调用圆形对象的draw方法 obj.draw() # 同理 rf = RectangleFactory() obj2 = rf.create() obj2.getShape() obj2.draw()
3.抽象工厂模式
以装电脑为例,产品族代表着各种配置,而产品等级代表着不同的配件。
当装机工程师要配置一台电脑,需要与配置工厂(AbstractFactory)与各类产品的基类关联。
代码如下:
######### 抽象工厂设计模式 ########## # 抽象工厂类(配置类) class AbstractFactory(object): computer_name = '' def createCpu(self): pass def createMainboard(self): pass # Intel配置类(CPU和主板都使用Intel的配置) class IntelFactory(AbstractFactory): computer_name = 'Intel I7-series computer ' def createCpu(self): return IntelCpu('I7-6500') def createMainboard(self): return IntelMainBoard('Intel-6000') # Amd配置类(CPU和主板都使用Amd的配置) class AmdFactory(AbstractFactory): computer_name = 'Amd 4 computer ' def createCpu(self): return AmdCpu('amd444') def createMainboard(self): return AmdMainBoard('AMD-4000') # CPU基类 class AbstractCpu(object): series_name = '' instructions = '' arch = '' # Intel的CPU class IntelCpu(AbstractCpu): def __init__(self, series): self.series_name = series # Amd的CPU class AmdCpu(AbstractCpu): def __init__(self, series): self.series_name = series # 主板基类 class AbstractMainboard(object): series_name = '' # Intel的主板 class IntelMainBoard(AbstractMainboard): def __init__(self, series): self.series_name = series # Amd的主板 class AmdMainBoard(AbstractMainboard): def __init__(self, series): self.series_name = series # 配置工程师类 class ComputerEngineer(object): # 使用配置工厂类来创建电脑 def makeComputer(self, computer_obj): self.prepareHardwares(computer_obj) # 准备硬件 def prepareHardwares(self, computer_obj): # 创建配置清单中的CPU self.cpu = computer_obj.createCpu() # 创建配置清单中的主板 self.mainboard = computer_obj.createMainboard() info = '''------- computer [%s] info: cpu: %s mainboard: %s -------- End -------- ''' % (computer_obj.computer_name, self.cpu.series_name, self.mainboard.series_name) print(info) if __name__ == "__main__": # 创建一个配置工程师实例 engineer = ComputerEngineer() # Intel配置对象 computer_factory = IntelFactory() # 按Intel配置配一台电脑 engineer.makeComputer(computer_factory) # AMD配置对象 computer_factory2 = AmdFactory() # 按AMD配置配一台电脑 engineer.makeComputer(computer_factory2)
4.建造者模式
这里的Product我们以人为例,人分为头、身体、手、腿四部分。
Builder是建造者的基类,实际的建造者使其子类ConcreteBuilder类。GetResult返回建造好的Product对象。
######### 建造者设计模式 ########## # 产品类(最终产出的东西) class Person(object): def __init__(self): self.head = "" self.body = "" self.arm = "" self.leg = "" def getPersonInfo(self): print("Head:" + self.head + " " + "Body:" + self.body + " " + "Arm:" + self.arm + " " + "Leg:" + self.leg) # 建造者基类 class PersonBuilder(object): def BuildHead(self): pass def BuildBody(self): pass def BuildArm(self): pass def BuildLeg(self): pass # 胖子建造者子类 class PersonFatBuilder(PersonBuilder): type = '胖子' def __init__(self): self.person = Person() def BuildHead(self): self.person.head = "构建%s的头" % self.type def BuildBody(self): self.person.body = "构建%s的身体" % self.type def BuildArm(self): self.person.arm = "构建%s的手" % self.type def BuildLeg(self): self.person.leg = "构建%s的腿" % self.type def getPerson(self): return self.person # 瘦子建造者子类 class PersonThinBuilder(PersonBuilder): type = '瘦子' def __init__(self): self.person = Person() def BuildHead(self): self.person.head = "构建%s的头" % self.type def BuildBody(self): self.person.body = "构建%s的身体" % self.type def BuildArm(self): self.person.arm = "构建%s的手" % self.type def BuildLeg(self): self.person.leg = "构建%s的腿" % self.type def getPerson(self): return self.person # 使用建造者的类(指挥官) class PersonDirector(object): def __init__(self, pb): self.pb = pb # 调用建造者里的各部位方法来创建一个人 def CreatePereson(self): self.pb.BuildHead() self.pb.BuildBody() self.pb.BuildArm() self.pb.BuildLeg() return self.pb.getPerson() def clientUI(): # 瘦子建造者实例 pb = PersonThinBuilder() # 指挥官类(使用瘦子创建者) pd = PersonDirector(pb) # 创建一个瘦子 created_thin_person = pd.CreatePereson() created_thin_person.getPersonInfo() # 胖子建造者实例 pb = PersonFatBuilder() # 指挥官类(使用胖子创建者) pd = PersonDirector(pb) # 创建一个胖子 created_fat_person = pd.CreatePereson() created_fat_person.getPersonInfo() if __name__ == '__main__': clientUI();
5.单例模式
单例模式参考:[Python自学] 设计模式之单例模式
三、结构型设计模式
在解决了对象的创建问题之后,对象的组成以及对象之间的依赖关系就成了开发人员关注的焦点,因为如何设计对象的结构、继承和依赖关系会影响到后续程序的维护性、代码的健壮性、耦合性等。对象结构的设计很容易体现出设计人员水平的高低,这里有7个具体的结构型模式可供研究,它们分别是:
- 外观模式(Facade)
- 适配器模式(Adapter)
- 代理模式(Proxy)
- 装饰模式(Decorator)
- 桥接模式(Bridge)
- 组合模式(Composite)
- 享元模式(Flyweight)
1.适配器模式
将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
######### 适配器模式 ########## # 将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 # 应用场景:希望复用一些现存的类,但是接口又与复用环境要求不一致。 def printInfo(info): print(info) # 球员基类 class Player(): name = '' def __init__(self, name): self.name = name def Attack(self, name): pass def Defense(self): pass # 前锋类 class Forwards(Player): def __init__(self, name): Player.__init__(self, name) def Attack(self): printInfo("前锋%s 进攻" % self.name) def Defense(self, name): printInfo("前锋%s 防守" % self.name) # 中锋类 class Center(Player): def __init__(self, name): Player.__init__(self, name) def Attack(self): printInfo("中锋%s 进攻" % self.name) def Defense(self): printInfo("中锋%s 防守" % self.name) # 后卫类 class Guards(Player): def __init__(self, name): Player.__init__(self, name) def Attack(self): printInfo("后卫%s 进攻" % self.name) def Defense(self): printInfo("后卫%s 防守" % self.name) # 外籍中锋(待适配类) # 中锋 class ForeignCenter(Player): name = '' def __init__(self, name): Player.__init__(self, name) # 不同的成员方法,需要适配成Attack方法 def ForeignAttack(self): printInfo("外籍中锋%s 进攻" % self.name) # 不同的成员方法,需要适配成Defense方法 def ForeignDefense(self): printInfo("外籍中锋%s 防守" % self.name) # 翻译类(适配类) class Translator(Player): foreignCenter = None # 将需要适配的类对象作为属性 def __init__(self, name): self.foreignCenter = ForeignCenter(name) # 将需要适配的类成员方法翻译成适配后的成员方法 def Attack(self): self.foreignCenter.ForeignAttack() def Defense(self): self.foreignCenter.ForeignDefense() def clientUI(): b = Forwards('巴蒂尔') m = Guards('姚明') # 直接使用适配类 ym = Translator('麦克格雷迪') b.Attack() m.Defense() ym.Attack() ym.Defense() return if __name__ == '__main__': clientUI()
2.桥接模式
在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式。
将抽象部分与实现部分分离,使它们都可以独立的变化。
class AbstractRoad(object): '''公路基类''' car = None class AbstractCar(object): '''车辆基类''' def run(self): pass class Street(AbstractRoad): '''市区街道''' def run(self): self.car.run() print("在市区街道上行驶") class SpeedWay(AbstractRoad): '''高速公路''' def run(self): self.car.run() print("在高速公路上行驶") class Car(AbstractCar): '''小汽车''' def run(self): print("小汽车在") class Bus(AbstractCar): '''公共汽车''' def run(self): print("公共汽车在") if __name__ == "__main__": #小汽车在高速上行驶 road1 = SpeedWay() road1.car = Car() road1.run() # road2 = SpeedWay() road2.car = Bus() road2.run()
3.组合模式
以树形结构组织类。
########### 组合模式 ########### class Store(object): '''店面基类''' # 添加店面 def add(self, store): pass # 删除店面 def remove(self, store): pass def pay_by_card(self): pass class BranchStore(Store): def __init__(self, name): self.name = name self.my_store_list = [] def pay_by_card(self): print("店面[%s]的积分已累加进该会员卡" % self.name) for s in self.my_store_list: s.pay_by_card() # 添加店面 def add(self, store): self.my_store_list.append(store) # 删除店面 def remove(self, store): self.my_store_list.remove(store) class JoinStore(Store): '''加盟店''' def __init__(self, name): self.name = name def pay_by_card(self): print("店面[%s]的积分已累加进该会员卡" % self.name) def add(self, store): print("无添加子店权限") def remove(self, store): print("无删除子店权限") if __name__ == "__main__": store = BranchStore("朝阳总店") branch = BranchStore("海滨分店") join_branch = JoinStore("昌平加盟1店") join_branch2 = JoinStore("昌平加盟2店") branch.add(join_branch) branch.add(join_branch2) store.add(branch) store.pay_by_card() print(store.my_store_list)
4.外观模式
为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
########## 外观模式 ########## def printInfo(info): print(info) class Stock(): name = '股票1' def buy(self): printInfo('买 ' + self.name) def sell(self): printInfo('卖 ' + self.name) class ETF(): name = '指数型基金' def buy(self): printInfo('买 ' + self.name) def sell(self): printInfo('卖 ' + self.name) class Future(): name = '期货' def buy(self): printInfo('买 ' + self.name) def sell(self): printInfo('卖 ' + self.name) class NationDebt(): name = '国债' def buy(self): printInfo('买 ' + self.name) def sell(self): printInfo('卖 ' + self.name) class Option(): name = '权证' def buy(self): printInfo('买 ' + self.name) def sell(self): printInfo('卖 ' + self.name) # 基金 class Fund(): def __init__(self): self.stock = Stock() self.etf = ETF() self.future = Future() self.debt = NationDebt() self.option = Option() def buyFund(self): self.stock.buy() self.etf.buy() self.debt.buy() self.future.buy() self.option.buy() def sellFund(self): self.stock.sell() self.etf.sell() self.future.sell() self.debt.sell() self.option.sell() def clientUI(): myFund = Fund() myFund.buyFund() myFund.sellFund() return if __name__ == '__main__': clientUI();
5.享元模式
使用一个字典保存所有对象,在产生对象时,将其类+参数作为键,键相同的对象,只会产生一份(有点像单例)。键不同则会产生新的对象。相当于相同属性的对象,直接共享使用,节省存储空间,所以叫享元模式。
########### 享元模式 ############ class FlyweightBase(object): _instances = dict() def __init__(self, *args, **kwargs): # 继承的子类必须初始化 raise NotImplementedError def __new__(cls, *args, **kwargs): # 类+参数作为键,如果已经存在,则返回存在的值(对象),如果不存在,则产生一个新实例,并返回 return cls._instances.setdefault( (cls, args, tuple(kwargs.items())), super(FlyweightBase, cls).__new__(cls) ) def test_data(self): pass class Spam(FlyweightBase): '''精子类''' def __init__(self, a, b): self.a = a self.b = b def test_data(self): print("精子准备好了", self.a, self.b) class Egg(FlyweightBase): '''卵类''' def __init__(self, x, y): self.x = x self.y = y def test_data(self): print("卵子准备好了", self.x, self.y) # 由于spam1和spam2都是产生自Spam类,而且参数都是1,'abc',所以键是一样的,spam1事先被创建并存于_instance中,spam2就不会被创建了 spam1 = Spam(1, 'abc') spam2 = Spam(1, 'abc') # spam3的参数不一样,所以被创建实例,保存在_instance中 spam3 = Spam(3, 'DEF') # egg1的类是Egg,所以也被创建实例,保存在_instance中 egg1 = Egg(1, 'abc') # spam1和spam2是同一个实例 print(id(spam1), id(spam2)) spam2.test_data() egg1.test_data() print(egg1._instances) print(egg1._instances.keys())
6.代理模式
使用一个代理类来帮另一个类做事情(调用其方法)。
######### 代理模式 ########## # 寄件者基类 class sender_base: def __init__(self): pass def send_something(self, something): pass # 寄件者子类 class send_class(sender_base): def __init__(self, receiver): self.receiver = receiver def send_something(self, something): print("SEND " + something + ' TO ' + self.receiver.name) # 代理类 class agent_class(sender_base): # 告诉代理接受者是谁 def __init__(self, receiver): self.send_obj = send_class(receiver) # 代理直接调用发送者的send_something方法发送东西给接受者 def send_something(self, something): self.send_obj.send_something(something) # 接受者类 class receive_class: def __init__(self, someone): self.name = someone if '__main__' == __name__: receiver = receive_class('Leo') agent = agent_class(receiver) agent.send_something('Cake') print(receiver.__class__) print(agent.__class__)
四、行为型设计模式
在对象的结构和对象的创建问题都解决了之后,就剩下对象的行为问题了,如果对象的行为设计的好,那么对象的行为就会更清晰,它们之间的协作效率就会提高,这里有11个具体的行为型模式可供研究,它们分别是:
- 模板方法模式(Template Method)
- 观察者模式(Observer)
- 状态模式(State)
- 策略模式(Strategy)
- 职责链模式(Chain of Responsibility)
- 命令模式(Command)
- 访问者模式(Visitor)
- 调停者模式(Mediator)
- 备忘录模式(Memento)
- 迭代器模式(Iterator)
- 解释器模式(Interpreter)
1.模板方法模式
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。
模板方法模式是一种基于继承的代码复用技术,它是一种类行为型模式。
模板方法模式是结构最简单的行为型设计模式,在其结构中只存在父类与子类之间的继承关系。通过使用模板方法模式,可以将一些复杂流程的实现步骤封装在一系列基本方法中,在抽象父类中提供一个称之为模板方法的方法来定义这些基本方法的执行次序,而通过其子类来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果。模板方法模式提供了一个模板方法来定义算法框架,而某些具体步骤的实现可以在其子类中完成。
优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
########## 模板方法模式 ########## # 注册基类,定义所有注册都需要的步骤 class Register(object): '''用户注册接口''' def register(self): pass def login(self): pass def auth(self): self.register() self.login() # QQ登录的具体实现 class RegisterByQQ(Register): '''qq注册''' def register(self): print("---用qq注册-----") def login(self): print('----用qq登录-----') # WeiChat登录的具体实现 class RegisterByWeiChat(Register): '''微信注册''' def register(self): print("---用微信注册-----") def login(self): print('----用微信登录-----') if __name__ == "__main__": register1 = RegisterByQQ() register1.login() register2 = RegisterByWeiChat() register2.login()
2.责任链模式
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
########## 责任链模式 ########## # 处理器基类, 其中包含下一个处理器 class BaseHandler(object): '''处理基类''' def successor(self, successor): # 与下一个责任者关联 self._successor = successor # 处理器1 class RequestHandlerL1(BaseHandler): '''第一级请求处理者''' name = "TeamLeader" def handle(self, request): if request < 500: print("审批者[%s],请求金额[%s],审批结果[审批通过]" % (self.name, request)) else: print("