目录篇: python相关目录篇 点击跳转

目录

  • 设计模式介绍
  • GoF该书设计了23个设计模式
  • 设计模式(Design Patterns)——可复用面向对象软件的基础
  • 设计模式分类
  • 1 创建型模式
  • 2 结构型模式
  • 3 行为型模式
  • 设计模式6大原则
  • 实战示例
  • 创建型
  • 0. 简单工厂模式(Simple Factory)
  • 1.工厂方法模式(Factory Method)
  • 2.抽象工厂模式(Abstract Factory)
  • 3.创建者模式(Builder)
  • 4.原型模式(Prototype)
  • 5.单例模式(Singleton)
  • 结构型
  • 6.适配器模式(Adapter)
  • 7.代理模式(Proxy)
  • 8.装饰模式(Decorator)
  • 9.桥模式(Bridge、多维度)
  • 10.组合模式(Composite)
  • 11.外观模式(Facade)
  • 12.享元模式(Flyweight)
  • 行为型
  • 13.观察者模式(Observer)
  • 14.状态模式(State)
  • 15.策略模式(Strategy)
  • 16.职责链模式(Chain of Responsibility)
  • 17.命令模式(Command)
  • ​        18.访问者模式(Visitor)
  • 19.调停者模式(Mediator)
  • 20.备忘录模式(Memento)
  • 21. 迭代器模式(Iterator)
  • ​        22. 解释器模式(Interpreter)
  • 23.模板方法(Template Method)

设计模式介绍

    GoF该书设计了23个设计模式

Python一切皆对象解释:我们用到的每个数字和字符串还是集合还是..本质都有相应的类对应如:name = “axc”可以通过点进行调用:name.strip()

    设计模式(Design Patterns)——可复用面向对象软件的基础

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。

    设计模式分类

经典的《设计模式》一书归纳出23种设计模式,这23种模式又可归为,创建型、结构型和行为型3大类

        1 创建型模式

前面讲过,社会化的分工越来越细,自然在软件设计方面也是如此,因此对象的创建和对象的使用分开也就成为了必然趋势。因为对象的创建会消耗掉系统的很多资源,所以单独对对象的创建进行研究,从而能够高效地创建对象就是创建型模式要探讨的问题。这里有6个具体的创建型模式可供研究,它们分别是:

0. 简单工厂模式(Simple Factory) #说明:严格来说,简单工厂模式不是GoF总结出来的23种设计模式之一。
    1.工厂方法模式(Factory Method)
    2.抽象工厂模式(Abstract Factory)
    3.创建者模式(Builder)
    4.原型模式(Prototype)
    5.单例模式(Singleton)

        2 结构型模式

在解决了对象的创建问题之后,对象的组成以及对象之间的依赖关系就成了开发人员关注的焦点,因为如何设计对象的结构、继承和依赖关系会影响到后续程序的维护性、代码的健壮性、耦合性等。对象结构的设计很容易体现出设计人员水平的高低,这里有7个具体的结构型模式可供研究,它们分别是:

6.适配器模式(Adapter)
    7.代理模式(Proxy)
    8.装饰模式(Decorator) 
    9.桥模式(Bridge、多维度)
    10.组合模式(Composite)   
    11.外观模式
    12.享元模式(Flyweight)

        3 行为型模式

在对象的结构和对象的创建问题都解决了之后,就剩下对象的行为问题了,如果对象的行为设计的好,那么对象的行为就会更清晰,它们之间的协作效率就会提高,这里有11个具体的行为型模式可供研究,它们分别是:

13.观察者模式(Observer)  #典型的发布订阅
   14.状态模式(State)
   15.策略模式(Strategy)
   16.职责链模式(Chain of Responsibility)
   17.命令模式(Command) 
   18.访问者模式(Visitor)  
   19.调停者模式(Mediator)
   20.备忘录模式(Memento) #如:虚拟机快照  #没讲(克隆:深copy、快照:浅copy)
   21. 迭代器模式(Iterator)   
   22. 解释器模式(Interpreter) 
   23.模板方法(Template Method)

设计模式6大原则

1、开闭原则(Open Close Principle

开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

2、里氏代换原则(Liskov Substitution Principle

里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科

3、依赖倒转原则(Dependence Inversion Principle

这个是开闭原则的基础,具体内容:是对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。

5、迪米特法则(最少知道原则)(Demeter Principle

为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle

原则是尽量使用合成/聚合的方式,而不是使用继承。

实战示例

创建型

         0. 简单工厂模式(Simple Factory)

说明:严格来说,简单工厂模式不是GoF总结出来的23种设计模式之一。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

意图:

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使个类的实例化延迟到其子类。

适用性:

当一个类不知道它所必须创建的对象的类的时候。
当一个类希望由它的子类来指定它所创建的对象的时候。
当类将创建对象的职责委托给多个子类中的某一个。

示例代码:

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-
'''
simple Factory Method
'''class Shape(object):'''父类'''def draw(self):raise NotImplementedErrorclass Circle(Shape):'''Shape子类'''def draw(self):print('draw circle')class Rectangle(Shape):'''Shape的子类'''def draw(self):print('draw Rectangle')class ShapeFactory(object):'''工厂模式:暴露给用户去调用的,用户可通过该类进行选择Shape的子类进行实例化'''def create(self, shape):if shape == 'Circle':return Circle()elif shape == 'Rectangle':return Rectangle()else:return Nonefac = ShapeFactory() #实例化工厂类
obj = fac.create('Circle') #实例化Shape的Circle子类
obj.draw()

执行结果:

Shape(父类 or 基类):提取出所有子类的重复方法代码
Circle(Shape子类 or 派生类):作用为画圆形
Rectangle(Shape子类 or 派生类):作用为画矩形
ShapeFactory(新式类):该类作用为用户可根据该类对象创建指定的Shape子类对象(Circle or Rectangle)
优点:客户端不需要修改代码。
缺点: 当需要增加新的运算类的时候,不仅需新加运算类,还要修改工厂类,违反了开闭原则。

        1.工厂方法模式(Factory Method)

这个和简单工厂有区别,简单工厂模式只有一个工厂,工厂方法模式对每一个产品都有相应的工厂
好处:增加一个运算类(例如N次方类),只需要增加运算类和相对应的工厂,两个类,不需要修改工厂类。
缺点:增加运算类,会修改客户端代码,工厂方法只是把简单工厂的内部逻辑判断移到了客户端进行

示例代码:

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-
'''
Factory Method
'''
'''
工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。
首先完全实现‘开-闭 原则’,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。   
工厂方法模式的对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个类将不在负责具体的产品生产,而是只制定一些规范,具体的生产工作由其子类去完成。在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。   
工厂方法模式(Factory Method pattern)是最典型的模板方法模式(Templete Method pattern)应用。'''class ShapeFactory(object):'''工厂类'''def getShape(self):return self.shape_nameclass Circle(ShapeFactory):def __init__(self):self.shape_name = "Circle"def draw(self):print('draw circle')class Rectangle(ShapeFactory):def __init__(self):self.shape_name = "Retangle"def draw(self):print('draw Rectangle')class ShapeInterfaceFactory(object):'''接口基类'''def create(self):'''把要创建的工厂对象装配进来'''raise  NotImplementedErrorclass ShapeCircle(ShapeInterfaceFactory):def create(self):return Circle()class ShapeRectangle(ShapeInterfaceFactory):def create(self):return Rectangle()shape_interface = ShapeCircle()
obj = shape_interface.create()
obj.getShape()
obj.draw()shape_interface2 = ShapeRectangle()
obj2 = shape_interface2.create()
obj2.draw()

执行结果:

ShapeFactory(父类 or 基类):提取出所有子类的重复方法代码
Circle(Shape子类 or 派生类):作用为画圆形
Rectangle(Shape子类 or 派生类):作用为画矩形
ShapeInterfaceFactory(父类 or 基类):提取出所有子类的重复方法代码
ShapeCircle(ShapeInterfaceFactory的子类 or 派生类):作用为创建指定的Circle对象
ShapeRectangle(ShapeInterfaceFactory的子类 or 派生类):作用为创建指定的Rectangle对象

        2.抽象工厂模式(Abstract Factory)

每一个模式都是针对一定问题的解决方案。抽象工厂模式与工厂方法模式的最大区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则需要面对多个产品等级结构。

  在学习抽象工厂具体实例之前,应该明白两个重要的概念:产品族和产品等级。

所谓产品族,是指位于不同产品等级结构中,功能相关联的产品组成的家族。比如AMD的主板、芯片组、CPU组成一个家族,Intel的主板、芯片组、CPU组成一个家族。而这两个家族都来自于三个产品等级:主板、芯片组、CPU。一个等级结构是由相同的结构的产品组成,示意图如下:

显然,每一个产品族中含有产品的数目,与产品等级结构的数目是相等的。产品的等级结构与产品族将产品按照不同方向划分,形成一个二维的坐标系。横轴表示产品的等级结构,纵轴表示产品族,上图共有两个产品族,分布于三个不同的产品等级结构中。只要指明一个产品所处的产品族以及它所属的等级结构,就可以唯一的确定这个产品。

  上面所给出的三个不同的等级结构具有平行的结构。因此,如果采用工厂方法模式,就势必要使用三个独立的工厂等级结构来对付这三个产品等级结构。由于这三个产品等级结构的相似性,会导致三个平行的工厂等级结构。随着产品等级结构的数目的增加,工厂方法模式所给出的工厂等级结构的数目也会随之增加。如下图:

那么,是否可以使用同一个工厂等级结构来对付这些相同或者极为相似的产品等级结构呢?当然可以的,而且这就是抽象工厂模式的好处。同一个工厂等级结构负责三个不同产品等级结构中的产品对象的创建。

可以看出,一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象。显然,这时候抽象工厂模式比简单工厂模式、工厂方法模式更有效率。对应于每一个产品族都有一个具体工厂。而每一个具体工厂负责创建属于同一个产品族,但是分属于不同等级结构的产品。

抽象工厂模式结构

  抽象工厂模式是对象的创建模式,它是工厂方法模式的进一步推广。

  假设一个子系统需要一些产品对象,而这些产品又属于一个以上的产品等级结构。那么为了将消费这些产品对象的责任和创建这些产品对象的责任分割开来,可以引进抽象工厂模式。这样的话,消费产品的一方不需要直接参与产品的创建工作,而只需要向一个公用的工厂接口请求所需要的产品。

  通过使用抽象工厂模式,可以处理具有相同(或者相似)等级结构中的多个产品族中的产品对象的创建问题。如下图所示:

  由于这两个产品族的等级结构相同,因此使用同一个工厂族也可以处理这两个产品族的创建问题,这就是抽象工厂模式。

  根据产品角色的结构图,就不难给出工厂角色的结构设计图。

可以看出,每一个工厂角色都有两个工厂方法,分别负责创建分属不同产品等级结构的产品对象。

抽象工厂的功能是为一系列相关对象或相互依赖的对象创建一个接口。一定要注意,这个接口内的方法不是任意堆砌的,而是一系列相关或相互依赖的方法。比如上面例子中的主板和CPU,都是为了组装一台电脑的相关对象。不同的装机方案,代表一种具体的电脑系列。

由于抽象工厂定义的一系列对象通常是相关或相互依赖的,这些产品对象就构成了一个产品族,也就是抽象工厂定义了一个产品族。

  这就带来非常大的灵活性,切换产品族的时候,只要提供不同的抽象工厂实现就可以了,也就是说现在是以一个产品族作为一个整体被切换。

在什么情况下应当使用抽象工厂模式

  1.一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。

  2.这个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。

  3.同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。(比如:Intel主板必须使用Intel CPU、Intel芯片组)

  4.系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。

抽象工厂模式的起源

  抽象工厂模式的起源或者最早的应用,是用于创建分属于不同操作系统的视窗构建。比如:命令按键(Button)与文字框(Text)都是视窗构建,在UNIX操作系统的视窗环境和Windows操作系统的视窗环境中,这两个构建有不同的本地实现,它们的细节有所不同。

  在每一个操作系统中,都有一个视窗构建组成的构建家族。在这里就是Button和Text组成的产品族。而每一个视窗构件都构成自己的等级结构,由一个抽象角色给出抽象的功能描述,而由具体子类给出不同操作系统下的具体实现。

抽象工厂模式的优点

  • 分离接口和实现

  客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口编程而已。也就是说,客户端从具体的产品实现中解耦。

  • 使切换产品族变得容易

  因为一个具体的工厂实现代表的是一个产品族,比如上面例子的从Intel系列到AMD系列只需要切换一下具体工厂。

抽象工厂模式的缺点

  • 不太容易扩展新的产品

  如果需要给整个产品族添加一个新的产品,那么就需要修改抽象工厂,这样就会导致修改所有的工厂实现类。

示例代码:

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-
'''
Abstract Factory
'''class AbstractFactory(object):computer_name = ''def createCpu(self):passdef createMainboard(self):passclass IntelFactory(AbstractFactory):computer_name = 'Intel I7-series computer 'def createCpu(self):return IntelCpu('I7-6500')def createMainboard(self):return IntelMainBoard('Intel-6000')class AmdFactory(AbstractFactory):computer_name = 'Amd 4 computer 'def createCpu(self):return AmdCpu('amd444')def createMainboard(self):return AmdMainBoard('AMD-4000')class AbstractCpu(object):series_name = ''instructions = ''arch=''class IntelCpu(AbstractCpu):def __init__(self,series):self.series_name = seriesclass AmdCpu(AbstractCpu):def __init__(self,series):self.series_name = seriesclass AbstractMainboard(object):series_name = ''class IntelMainBoard(AbstractMainboard):def __init__(self,series):self.series_name = seriesclass AmdMainBoard(AbstractMainboard):def __init__(self,series):self.series_name = seriesclass ComputerEngineer(object):def makeComputer(self,factory_obj):self.prepareHardwares(factory_obj)def prepareHardwares(self,factory_obj):self.cpu = factory_obj.createCpu()self.mainboard = factory_obj.createMainboard()info = '''------- computer [%s] info:cpu: %smainboard: %s-------- End --------'''% (factory_obj.computer_name,self.cpu.series_name,self.mainboard.series_name)print(info)
if __name__ == "__main__":engineer = ComputerEngineer()   #装机工程师intel_factory = IntelFactory()    #intel工厂engineer.makeComputer(intel_factory)amd_factory = AmdFactory()      #adm工厂engineer.makeComputer(amd_factory)

执行结果:

AbstractFactory(父类or基类 )
    IntelFactory(AbstractFactory的子类or派生类):作用为进行了创建自定品牌的零件
    AmdFactory(AbstractFactory的子类or派生类):作用为进行了创建自定品牌的零件
AbstractCpu(父类or基类 )
    IntelCpu(AbstractCpu的子类or派生类):作用为记录cup的型号
    AmdCpu(AbstractCpu的子类or派生类):作用为记录cup的型号
AbstractMainboard(父类or基类 )
    IntelMainBoard(AbstractMainboard的子类or派生类):作用为记录主板的型号
    AmdMainBoard(AbstractMainboard的子类or派生类):作用为记录主板的型号
ComputerEngineer(新式类):作用为根据工厂对象(如IntelFactory())让其组装自身型号的零件

抽象工厂和工厂模式的对比区别:
抽象工厂:规定死了,依赖限制,假上面实验,你用intel的机器只能配置intel的CPU不能配置AMD的CPU(由各自的工厂指定自己的产品生产品牌)
工厂模式:不是固定死的,举例:你可使用intel的机器配置AMD的CPU

        3.创建者模式(Builder)

意图:

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

适用性:

当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。

当构造过程必须允许被构造的对象有不同的表示时。

示例代码:

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-
'''
Builder
'''#建造者模式
#相关模式:思路和模板方法模式很像,模板方法是封装算法流程,对某些细节,提供接口由子类修改,建造者模式更为高层一点,将所有细节都交由子类实现。
# 建造者模式:将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示。
# 基本思想
# 某类产品的构建由很多复杂组件组成;
# 这些组件中的某些细节不同,构建出的产品表象会略有不同;
# 通过一个指挥者按照产品的创建步骤来一步步执行产品的创建;
# 当需要创建不同的产品时,只需要派生一个具体的建造者,重写相应的组件构建方法即可。def printInfo(info):print(info)#建造者基类
class PersonBuilder():def BuildHead(self):passdef BuildBody(self):passdef BuildArm(self):passdef BuildLeg(self):pass#胖子
class PersonFatBuilder(PersonBuilder):type = '胖子'def BuildHead(self):printInfo("构建%s的大。。。。。头" % self.type)def BuildBody(self):printInfo("构建%s的身体" % self.type)def BuildArm(self):printInfo("构建%s的手" % self.type)def BuildLeg(self):printInfo("构建%s的脚" % self.type)#瘦子
class PersonThinBuilder(PersonBuilder):type = '瘦子'def BuildHead(self):printInfo("构建%s的头" % self.type)def BuildBody(self):printInfo("构建%s的身体" % self.type)def BuildArm(self):printInfo("构建%s的手" % self.type)def BuildLeg(self):printInfo("构建%s的脚" % self.type)#指挥者
class PersonDirector():pb = None;def __init__(self, pb):self.pb = pbdef CreatePereson(self):self.pb.BuildHead()self.pb.BuildBody()self.pb.BuildArm()self.pb.BuildLeg()def clientUI():pb = PersonThinBuilder()pd = PersonDirector(pb)pd.CreatePereson()pb2 = PersonFatBuilder()#pd = PersonDirector(pb)pd.pb = pb2pd.CreatePereson()returnif __name__ == '__main__':clientUI();

执行结果:

personBuilder(父类 or 基类)
PersonFatBuilder(personBuilder的子类 or派生类):作用为创建一个胖子的身体部位
PersonThinBuilder(personBuilder的子类 or派生类):作用为创建一个瘦子的身体部位
PersonDirector(新式类):作用为根据personBuilder子类对象(如PersonFatBuilder())让其创建其身体部位

        4.原型模式(Prototype)

意图:

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

适用性:

当要实例化的类是在运行时刻指定时,例如,通过动态装载;或者为了避免创建一个与产品类层次平行的工厂类层次时;或者当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

示例代码:

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-
'''
Prototype
'''import copyclass Prototype:def __init__(self):self._objects = {}def register_object(self, name, obj):"""Register an object"""self._objects[name] = objdef unregister_object(self, name):"""Unregister an object"""del self._objects[name]def clone(self, name, **attr):"""Clone a registered object and update inner attributes dictionary"""obj = copy.deepcopy(self._objects.get(name))obj.__dict__.update(attr)return objdef main():class A:def __str__(self):return "I am A"a = A()prototype = Prototype()prototype.register_object('a', a)b = prototype.clone('a', a=1, b=2, c=3)print(a)print(b.__dict__)print(b.a, b.b, b.c)if __name__ == '__main__':main()

执行结果:

通过执行结果我们可以看出:通过一个类的方法复制a对象,进行a对象的变量赋值

        5.单例模式(Singleton)

意图:

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

适用性:

当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。

当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

示例代码:

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-
'''
Singleton
'''# 实现__new__方法
# 并在将一个类的实例绑定到类变量_instance上,
# 如果cls._instance为None说明该类还没有实例化过,实例化该类,并返回
# 如果cls._instance不为None,直接返回cls._instance
class Singleton(object):def __new__(cls, *args, **kwargs):if not hasattr(cls, '_instance'):# cls = a = MyClass('Burgess')# 判断是否有a该实例存在,前面是否已经有人实例过,如果内存没有该实例...往下执行# 需要注明该父类的内存空间内最多允许相同名字子类的实例对象存在1个(不可多个)orig = super(Singleton, cls)  # farther classcls._instance = orig.__new__(cls)# orig =让cls继承指定的父类 Singleton# cls._instance = 创建了MyClass('Burgess') 该实例# 这两句相当于外面的 a= MyClass('Burgess')return cls._instance  # 具体的实例class MyClass(Singleton):def __init__(self, name):self.name = nameclass Nana(Singleton):def __init__(self, name):self.name = namea = MyClass("Burgess")
print(a.name)
b = MyClass("Crystal")
print(a.name)
print(b.name)
b.name = 'xx'
print(a.name)
print(b.name)

执行结果:

通过执行结果我们可以看出:一个类永远只允许一个实例化对象,不管多少个进行实例化,都返回第一个实例化的对象

结构型

        6.适配器模式(Adapter)

意图:

将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

适用性:

你想使用一个已经存在的类,而它的接口不符合你的需求。

你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。

(仅适用于对象Adapter )你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。

示例代码:

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-
'''
Adapter
'''
#适配器模式
# 将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
# 应用场景:希望复用一些现存的类,但是接口又与复用环境要求不一致。def printInfo(info):print(info)#球员类
class Player():name = ''def __init__(self,name):self.name = namedef Attack(self,name):passdef Defense(self):pass#前锋
class Forwards(Player):def __init__(self,name):Player.__init__(self,name)def Attack(self):printInfo("前锋%s 进攻" % self.name)def Defense(self):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)def ForeignAttack(self):printInfo("外籍中锋%s 进攻" % self.name)def ForeignDefense(self):printInfo("外籍中锋%s 防守" % self.name)#翻译(适配类)
class Translator(Player):foreignCenter = Nonedef __init__(self,name):self.foreignCenter = ForeignCenter(name)def Attack(self):self.foreignCenter.ForeignAttack()def Defense(self):self.foreignCenter.ForeignDefense()def clientUI():b = Forwards('巴蒂尔')ym = Guards('姚明')m = Translator('麦克格雷迪')b.Attack()m.Defense()ym.Attack()b.Defense()returnif __name__ == '__main__':clientUI()

执行结果:

Player:(父类or基类)
国内
Forwards(Player的子类or派生类):作用为国内球员的动作方法
Center(Player的子类or派生类):作用为国内球员的动作方法
Guards(Player的子类or派生类):作用为国内球员的动作方法
国外:
ForeignCenter(Player的子类or派生类):作用为国外球员的动作方法(动作虽然一样但是动作方法的名字和国内动作方法的名字不一样)
Translator(Player的子类or派生类):作用为适配器,国内球员的动作方法的名字一样(但是方法内调用了国外球员对象的动作方法)

        7.代理模式(Proxy)

意图:为其他对象提供一种代理以控制对这个对象的访问。

主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

何时使用:想在访问一个类时做一些控制。

如何解决:增加中间层。

关键代码:实现与被代理类组合。

应用实例: 1、Windows 里面的快捷方式。 2、猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。 3、买火车票不一定在火车站买,也可以去代售点。 4、一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。 5、spring aop。

优点: 1、职责清晰。 2、高扩展性。 3、智能化。

缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

使用场景:按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。

代码示例

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-'''
Proxy
'''# 代理模式
# 应用特性:需要在通信双方中间需要一些特殊的中间操作时引用,多加一个中间控制层。
# 结构特性:建立一个中间类,创建一个对象,接收一个对象,然后把两者联通起来class sender_base:def __init__(self):passdef send_something(self, something):passclass send_class(sender_base):def __init__(self, receiver):self.receiver = receiverdef 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)def send_something(self, something):self.send_obj.send_something(something)class receive_class:def __init__(self, someone):self.name = someoneif '__main__' == __name__:receiver = receive_class('Burgess')agent = agent_class(receiver)agent.send_something('agentinfo')print(receiver.__class__)print(agent.__class__)

   执行结果:

sender_base(父类or基类)
send_class(sender_base的子类or派生类):作用为发送信息
agent_class(sender_base的子类or派生类):作用为代理(发送信息给接受者)
receive_class(新式类):作用为实例化一个接受者

        8.装饰模式(Decorator)

意图: 
动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator 模式相比生成子类更为灵活。 
适用性:

在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

处理那些可以撤消的职责。

当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

代码示例:

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-'''
Decorator
'''class foo(object):def f1(self):print("original f1")def f2(self):print("original f2")class foo_decorator(object):def __init__(self, decoratee):self._decoratee = decorateedef f1(self):print("decorated f1")self._decoratee.f1()def __getattr__(self, name):return getattr(self._decoratee, name)u = foo()
v = foo_decorator(u)
v.f1()
v.f2()

执行结果:

从代码可以了解执行一个类对象可以通过另外一个类(装饰器)代替其执行(不改变被装饰的类的源码)

        9.桥模式(Bridge、多维度)

生活中的一个例子:就拿汽车在路上行驶的来说。即有小汽车又有公共汽车,它们都不但能在市区中的公路上行驶,也能在高速公路上行驶。这你会发现,对于交通工具(汽车)有不同的类型,然而它们所行驶的环境(路)也在变化,在软件系统中就要适应两个方面的变化?怎样实现才能应对这种变化呢?
概述:
在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式。
意图:将抽象部分与实现部分分离,使它们都可以独立的变化。——《设计模式》GOF效果及实现要点:
1.Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。
2.所谓抽象和实现沿着各自维度的变化,即“子类化”它们,得到各个子类之后,便可以任意它们,从而获得不同路上的不同汽车。
3.Bridge模式有时候类似于多继承方案,但是多继承方案往往违背了类的单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决方法。
4.Bridge模式的应用一般在“两个非常强的变化维度”,有时候即使有两个变化的维度,但是某个方向的变化维度并不剧烈——换言之两个变化不会导致纵横交错的结果,并不一定要使用Bridge模式。适用性:在以下的情况下应当使用桥梁模式:
1.如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的联系。
2.设计要求实现化角色的任何改变不应当影响客户端,或者说实现化角色的改变对客户端是完全透明的。
3.一个构件有多于一个的抽象化角色和实现化角色,系统需要它们之间进行动态耦合。
4.虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。
总结:Bridge模式是一个非常有用的模式,也非常复杂,它很好的符合了开放-封闭原则和优先使用对象,而不是继承这两个面向对象原则

示例代码

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-
'''
Bridge
'''
class AbstractRoad(object):'''路基类'''car = Noneclass AbstractCar(object):'''车辆基类'''def run(self):raise NotImplementedErrorclass 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()road3 = Street()road3.car = Bus()road3.run()

执行结果:

AbstractRoad(父类or基类)
Street(AbstractRoad的子类or派生类):作用为执行了车辆对象的方法
SpeedWay(AbstractRoad的子类or派生类):作用为执行了车辆对象的方法

AbstractCar(父类or基类)
Car(AbstractCar的子类or派生类):作用为被调用执行
Bus(AbstractCar的子类or派生类):作为为被调用执行

应用设计模式:
       桥接模式(Bridge)来做(多维度变化);
       结合上面的例子,增加一个维度"人",不同的人开着不同的汽车在不同的路上行驶(三个维度);
       结合上面增加一个类"人",并重新调用.
代码实现:

示例代码

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-
'''
应用设计模式(Bridge多维度)
'''
class AbstractRoad(object):'''公路基类'''car = Noneclass AbstractCar(object):'''车辆基类'''def run(self):passclass People(object):passclass 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):'''公共汽车'''road = Nonedef run(self):print("公共汽车在")#加上人
class Man(People):def drive(self):print("男人开着")self.road.run()
#加上人
class Woman(People):def drive(self):print("女人开着")self.road.run()if __name__ == "__main__":#小汽车在高速上行驶road1 = SpeedWay()road1.car = Car()road1.run()#road2 = SpeedWay()road2.car = Bus()road2.run()#人开车road3 = Street()road3.car = Car()p1 = Man()p1.road = road3p1.drive()p2 = Woman()p2.road = road3p2.drive()

执行结果:

AbstractRoad(父类or基类)
Street(AbstractRoad的子类or派生类):作用为执行了车辆对象的方法
SpeedWay(AbstractRoad的子类or派生类):作用为执行了车辆对象的方法

AbstractCar(父类or基类)
Car(AbstractCar的子类or派生类):作用为被调用执行
Bus(AbstractCar的子类or派生类):作为为被调用执行

People(父类or基类)
Man(People的子类or派生类):作用为执行了路对象的方法
Woman(People的子类or派生类):作用为执行了路对象的方法

        10.组合模式(Composite)

意图:

将对象组合成树形结构以表示“部分-整体”的层次结构。C o m p o s i t e 使得用户对单个对象和组合对象的使用具有一致性。

适用性:

你想表示对象的部分-整体层次结构。

你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

示例代码

__author__ = "Burgess Zheng"
# !/usr/bin/env python
# -*- coding:utf-8 -*-"""
Composite
"""class Component:def __init__(self, strName):self.m_strName = strNamedef Add(self, com):passdef Display(self, nDepth):passclass Leaf(Component):def Add(self, com):print("leaf can't add")def Display(self, nDepth):strtemp = "-" * nDepthstrtemp = strtemp + self.m_strNameprint(strtemp)class Composite(Component):def __init__(self, strName):self.m_strName = strNameself.c = []def Add(self, com):self.c.append(com)def Display(self, nDepth):strtemp = "-" * nDepthstrtemp = strtemp + self.m_strNameprint(strtemp)for com in self.c:com.Display(nDepth + 2)if __name__ == "__main__":p = Composite("Wong")p.Add(Leaf("Lee"))p.Add(Leaf("Zhao"))p1 = Composite("Wu")p1.Add(Leaf("San"))p.Add(p1)p.Display(1)

执行结果:

从执行结果可以看出,通过一个类对象把其他的类对象添加到自身的变量列表,然后循环执行该列表,执行所有对象的相同方法

        11.外观模式(Facade)

意图:

为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

适用性:

当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。Facade 可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过facade层。

客户程序与抽象类的实现部分之间存在着很大的依赖性。引入facade 将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。

当你需要构建一个层次结构的子系统时,使用facade模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过facade进行通讯,从而简化了它们之间的依赖关系。

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-
'''
Facade
'''#外观模式(Facade),为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使得这一子系统更加容易使用。
# 在以下情况下可以考虑使用外观模式:
# (1)设计初期阶段,应该有意识的将不同层分离,层与层之间建立外观模式。
# (2) 开发阶段,子系统越来越复杂,增加外观模式提供一个简单的调用接口。
# (3) 维护一个大型遗留系统的时候,可能这个系统已经非常难以维护和扩展,但又包含非常重要的功能,为其开发一个外观类,以便新系统与其交互。# 优点编辑
# (1)实现了子系统与客户端之间的松耦合关系。
# (2)客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目,并使得子系统使用起来更加容易。def printInfo(info):print(info)class Stock():name = '股票'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()returnif __name__ == '__main__':clientUI()

执行结果:

从执行结果可以看出:一个类被实例化成对象,该对象的初始化进行了实例化所有其他的类对象,通过调用该类的方法执行所有其他类对象的相同方法
   

        12.享元模式(Flyweight)

意图:

运用共享技术有效地支持大量细粒度的对象。

适用性:

一个应用程序使用了大量的对象。

完全由于使用大量的对象,造成很大的存储开销。

对象的大多数状态都可变为外部状态。

如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。

应用程序不依赖于对象标识。由于Flyweight 对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。

代码示例:

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-
'''
Flyweight
'''
class FlyweightBase(object):_instances = dict()  #皴法实例化的对象内存地址def __init__(self,*args,**kwargs):#继承的子类必须初始化raise NotImplementedErrordef __new__(cls, *args, **kwargs):print(cls._instances,type(cls))  #cls 就是你要实例化的子类如:obj = Spam(1,abc)return cls._instances.setdefault((cls,args,tuple(kwargs.items())), #key   (实例和参数)obj = Spam(y,x)super(FlyweightBase,cls).__new__(cls)  # value  #实例化新的对象的内存地址# 调用自身的_instances字典,如果没有往父类找_instances字典# setdefault:判断_instances字典是否有该key:obj = Spam(y,x)实例 ,#               如果有,返回该key的value(上次实例化对象(内存地址))# setdefault: 如果找不到key:obj = Spam(y,x)实例 ,就在_instances字典就创建该key,value为新实例化对象(内存地址)#               返回该新创建key的value(该次实例化的对象(内存地址)# 这也就说明你实例化对象的时候,如果形参相同的话,不用实例化,直接返回已存在的实例的内存))
class Spam(FlyweightBase):'''精子类'''def test_data(self):passdef __init__(self,a,b):self.a = aself.b = bdef test_data(self):print("精子准备好了",self.a,self.b)
class Egg(FlyweightBase):'''卵类'''def __init__(self,x,y):self.x = xself.y = ydef test_data(self):print("卵子准备好了",self.x,self.y)spam1 = Spam(1,'abc')
spam2 = Spam(1,'abc')
spam3 = Spam(3,'DEF')egg1 = Egg(1,'abc')
print(id(spam1),id(spam2),id(spam3))#egg2 = Egg(4,'abc')
# assert spam1 is spam2
# assert egg1 is not spam1
# print(id(spam1),id(spam2))
# spam2.test_data()
# egg1.test_data()
# print(egg1._instances)
# print(egg1._instances.keys())

执行结果:

通过代码了解:在单例的基础上做了改动,也就是当你实例化一个对象,就判断你实例化的该对象(包含形参)是否存在父类的指定的字典,存在就把之前实例化对象返回给你(等于没创建新的示例,而是赋值多一个变量而已,指向同一个内存地址),如果不存在,就创建新的实例化对象返回,并且存放在指定字典

行为型

        13.观察者模式(Observer)

意图:

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。

适用性:

当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。

当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。

当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。

示例代码:

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-'''
Observer
'''
# 观察者(Observer)模式又名发布-订阅(Publish/Subscribe)模式
# 当我们希望一个对象的状态发生变化,那么依赖与它的所有对象都能相应变化(获得通知),那么就可以用到Observer模式, 其中的这些依赖对象就是观察者的对象,那个要发生变化的对象就是所谓’观察者’class ObserverBase(object):'''观察者基类''' #放哨者def __init__(self):self._observerd_list = [] #被通知对象def attach(self,observe_subject):'''添加要观察的对象:param observe_subject::return:'''if observe_subject not in self._observerd_list:self._observerd_list.append(observe_subject)print("[%s]已经将[%s]加入观察队列..."%(self.name,observe_subject) )def detach(self,observe_subject):'''解除观察关系:param observe_subject::return:'''try:self._observerd_list.remove(observe_subject)print("不再观察[%s]" %observe_subject)except ValueError:passdef notify(self):'''通知所有被观察者:return:'''for objserver in self._observerd_list:objserver.update(self)class Observer(ObserverBase):'''观察者类'''def __init__(self,name):super(Observer,self).__init__()self.name = nameself._msg = ''@property  #外部执行d.eat 去掉括号def msg(self):'''当前状况:return:'''return self._msg@msg.setter  #设置属性(一个方法变成一个静态的属性)def msg(self,content):self._msg = contentself.notify()
#目前结论:一个方法变成一个静态的属性 (装饰了@property)
#通过另外一个相同名字的方法(装饰@msg.setter )进行修改该属性
#简单: d = Observer('xxx')#print(d.msg)  结果:空#d.msg = 'xxx'# #这种形式调用该对象有装饰setter的方法,xxx作为形参#print(d.msg)  结果:xxxclass GCDViewer(object):'''共军被观察者'''def update(self,observer_subject):print("共军:收到[%s]消息[%s] "%(observer_subject.name,observer_subject.msg) )class GMDViewer(object):'''国军被观察者'''def update(self,observer_subject):print("国军:收到[%s]消息[%s] "%(observer_subject.name,observer_subject.msg) )if __name__ == "__main__":observer1 = Observer("共军放哨者")observer2 = Observer("国军放哨者")gongjun1 = GCDViewer()guojun1 = GMDViewer()observer1.attach(gongjun1)observer1.attach(guojun1)observer2.attach(guojun1)observer1.msg = "\033[32;1m敌人来了...\033[0m"observer2.msg ="\033[31;1m前方发现敌人,请紧急撤离,不要告诉共军\033[0m"

   执行结果:

通过代码了解其实就是发布订阅模式

        14.状态模式(State)

意图:

允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

适用性:

一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。

一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常, 有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

__author__ = "Burgess Zheng"
# !/usr/bin/env python
# -*- coding:utf-8 -*-'''
State
'''class State(object):"""Base state. This is to share functionality"""def scan(self):"""Scan the dial to the next station"""self.pos += 1if self.pos == len(self.stations):self.pos = 0print("Scanning... Station is", self.stations[self.pos], self.name)class AmState(State):def __init__(self, radio):self.radio = radioself.stations = ["1250", "1380", "1510"]self.pos = 0self.name = "AM"def toggle_amfm(self):print("Switching to FM")self.radio.state = self.radio.fmstateclass FmState(State):def __init__(self, radio):self.radio = radioself.stations = ["81.3", "89.1", "103.9"]self.pos = 0self.name = "FM"def toggle_amfm(self):print("Switching to AM")self.radio.state = self.radio.amstateclass Radio(object):"""A radio.     It has a scan button, and an AM/FM toggle switch."""def __init__(self):"""We have an AM state and an FM state"""self.amstate = AmState(self)self.fmstate = FmState(self)self.state = self.amstatedef toggle_amfm(self):self.state.toggle_amfm()def scan(self):self.state.scan()# Test our radio out
if __name__ == '__main__':radio = Radio()actions = [radio.scan] * 2 + [radio.toggle_amfm] + [radio.scan] * 2actions = actions * 2for action in actions:action()

执行结果

通过代码:就是通过一个对象的方法调用已经存在其他类对象的状态
   

        15.策略模式(Strategy)

意图:

定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

适用性:

许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。

需要使用一个算法的不同变体。例如,你可能会定义一些反映不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时[H087] ,可以使用策略模式。

算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。

一个类定义了多种行为, 并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句

示例代码

__author__ = "Burgess Zheng"
# !/usr/bin/env python
# -*- coding:utf-8 -*-'''
Strategy
'''
class TravelStrategy(object):'''出行策略'''def travelAlgorithm(self):passclass AirplaneStrategy(TravelStrategy):def travelAlgorithm(self):print("坐飞机出行....")class TrainStrategy(TravelStrategy):def travelAlgorithm(self):print("坐高铁出行....")class CarStrategy(TravelStrategy):def travelAlgorithm(self):print("自驾出行....")class BicycleStrategy(TravelStrategy):def travelAlgorithm(self):print("骑车出行....")class TravelInterface(object):def __init__(self,travel_strategy):self.travel_strategy = travel_strategydef set_strategy(self,travel_strategy):self.travel_strategy = travel_strategydef travel(self):return self.travel_strategy.travelAlgorithm()#坐飞机
travel = TravelInterface(AirplaneStrategy())travel.travel()#改开车
travel.set_strategy(CarStrategy())
travel.travel()

执行结果

        16.职责链模式(Chain of Responsibility)

意图:

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

适用性:

有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。

你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。

可处理一个请求的对象集合应被动态指定。

代码示例:

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-'''
Chain of Responsibility
'''# 职责链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
# 适用场景:
# 1、有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定;
# 2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求;
# 3、处理一个请求的对象集合应被动态指定。class BaseHandler(object):'''处理基类'''def successor(self,successor): #next_handler#与下一个责任者关联self._successor = successorclass RequestHandlerL1(BaseHandler):'''第一级请求处理者'''name = "TeamLeader"def handle(self,request):if request < 500 :print("审批者[%s],请求金额[%s],审批结果[审批通过]"%(self.name,request))else:print("\033[31;1m[%s]无权审批,交给下一个审批者\033[0m" %self.name)self._successor.handle(request)class RequestHandlerL2(BaseHandler):'''第二级请求处理者'''name = "DeptManager"def handle(self,request):if request < 5000 :print("审批者[%s],请求金额[%s],审批结果[审批通过]"%(self.name,request))else:print("\033[31;1m[%s]无权审批,交给下一个审批者\033[0m" %self.name)self._successor.handle(request)class RequestHandlerL3(BaseHandler):'''第三级请求处理者'''name = "CEO"def handle(self,request):if request < 10000 :print("审批者[%s],请求金额[%s],审批结果[审批通过]"%(self.name,request))else:print("\033[31;1m[%s]要太多钱了,不批\033[0m"%self.name)#self._successor.handle(request)class RequestAPI(object):h1 = RequestHandlerL1()h2 = RequestHandlerL2()h3 = RequestHandlerL3()h1.successor(h2)h2.successor(h3)def __init__(self,name,amount):self.name = nameself.amount = amountdef handle(self):'''统一请求接口'''self.h1.handle(self.amount)if __name__ == "__main__":r1 = RequestAPI("Burgess",8000)r1.handle()print(r1.__dict__)

执行结果:

#如OA系统 不同等级领导批示资金大小权限不同(根据资金大小自动流转到责任人)
简单解释:
1接口类对象内把最高层级处理者领对象赋值到比其低一层级处理者对象(层级高的对象作为形参实例化层级低对象)以此类推
2.实例化接口类,把申请人和申请资金传递进去,执行该接口类对象处理方法
3.该处理方法执行最低层级领导的处理方法(进行判断该资金是否自己有权限处理,没权限处理就调用比其高一层级的处理对象进行处理,以此类推)

        17.命令模式(Command)

意图:

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。

适用性:

抽象出待执行的动作以参数化某对象,你可用过程语言中的回调(call back)函数表达这种参数化机制。所谓回调函数是指函数先在某处注册,而它将在稍后某个需要的时候被调用。Command 模式是回调机制的一个面向对象的替代品。

在不同的时刻指定、排列和执行请求。一个Command对象可以有一个与初始请求无关的生存期。如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可将负责该请求的命令对象传送给另一个不同的进程并在那儿实现该请求。

支持取消操作。Command的Excute 操作可在实施操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。Command 接口必须添加一个Unexecute操作,该操作取消上一次Execute调用的效果。执行的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用Unexecute和Execute来实现重数不限的“取消”和“重做”。

支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍。在Command接口中添加装载操作和存储操作,可以用来保持变动的一个一致的修改日志。从崩溃中恢复的过程包括从磁盘中重新读入记录下来的命令并用Execute操作重新执行它们。

用构建在原语操作上的高层操作构造一个系统。这样一种结构在支持事务( transaction)的信息系统中很常见。一个事务封装了对数据的一组变动。Command模式提供了对事务进行建模的方法。Command有一个公共的接口,使得你可以用同一种方式调用所有的事务。同时使用该模式也易于添加新事务以扩展系统。

代码示例

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-"""
Command
"""
import osclass MoveFileCommand(object):def __init__(self, src, dest):self.src = srcself.dest = destdef execute(self):self()def __call__(self):print('renaming {} to {}'.format(self.src, self.dest))os.rename(self.src, self.dest)def undo(self):print('renaming {} to {}'.format(self.dest, self.src))os.rename(self.dest, self.src)if __name__ == "__main__":command_stack = []# commands are just pushed into the command stackcommand_stack.append(MoveFileCommand('foo.txt', 'foo1.txt'))command_stack.append(MoveFileCommand('bar.txt', 'bar1.txt'))# they can be executed later onfor cmd in command_stack:cmd.execute()# and can also be undone at willfor cmd in reversed(command_stack):cmd.undo()

执行结果:


        18.访问者模式(Visitor)  

意图:

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。TemplateMethod 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

适用性:

一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。

各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。这是Opdyke和Johnson所描述过的“重分解以一般化”的一个很好的例子[OJ93]。首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。

控制子类扩展。模板方法只在特定点调用“hook ”操作(参见效果一节),这样就只允许在这些点进行扩展

代码示例:

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-'''
Visitor
'''class Node(object):passclass A(Node):passclass B(Node):passclass C(A, B):passclass Visitor(object):def visit(self, node, *args, **kwargs):meth = Nonefor cls in node.__class__.__mro__:meth_name = 'visit_' + cls.__name__meth = getattr(self, meth_name, None)if meth:breakif not meth:meth = self.generic_visitreturn meth(node, *args, **kwargs)def generic_visit(self, node, *args, **kwargs):print('generic_visit ' + node.__class__.__name__)def visit_B(self, node, *args, **kwargs):print('visit_B ' + node.__class__.__name__)a = A()
b = B()
c = C()
visitor = Visitor()
visitor.visit(a)
visitor.visit(b)
visitor.visit(c)

执行结果:

 

        19.调停者模式(Mediator)

意图:

用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

适用性:

一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。

一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。

想定制一个分布在多个类中的行为,而又不想生成太多的子类。

代码示例

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-'''
Mediator
'''import timeclass TC:def __init__(self):self._tm = tmself._bProblem = 0def setup(self):print("Setting up the Test")time.sleep(1)self._tm.prepareReporting()def execute(self):if not self._bProblem:print("Executing the test")time.sleep(1)else:print("Problem in setup. Test not executed.")def tearDown(self):if not self._bProblem:print("Tearing down")time.sleep(1)self._tm.publishReport()else:print("Test not executed. No tear down required.")def setTM(self, TM):self._tm = tmdef setProblem(self, value):self._bProblem = valueclass Reporter:def __init__(self):self._tm = Nonedef prepare(self):print("Reporter Class is preparing to report the results")time.sleep(1)def report(self):print("Reporting the results of Test")time.sleep(1)def setTM(self, TM):self._tm = tmclass DB:def __init__(self):self._tm = Nonedef insert(self):print("Inserting the execution begin status in the Database")time.sleep(1)#Following code is to simulate a communication from DB to TCimport randomif random.randrange(1, 4) == 3:return -1def update(self):print("Updating the test results in Database")time.sleep(1)def setTM(self, TM):self._tm = tmclass TestManager:def __init__(self):self._reporter = Noneself._db = Noneself._tc = Nonedef prepareReporting(self):rvalue = self._db.insert()if rvalue == -1:self._tc.setProblem(1)self._reporter.prepare()def setReporter(self, reporter):self._reporter = reporterdef setDB(self, db):self._db = dbdef publishReport(self):self._db.update()rvalue = self._reporter.report()def setTC(self, tc):self._tc = tcif __name__ == '__main__':reporter = Reporter()db = DB()tm = TestManager()tm.setReporter(reporter)tm.setDB(db)reporter.setTM(tm)db.setTM(tm)# For simplification we are looping on the same test.# Practically, it could be about various unique test classes and their# objectswhile (True):tc = TC()tc.setTM(tm)tm.setTC(tc)tc.setup()tc.execute()tc.tearDown()

执行结果:

        20.备忘录模式(Memento) 

意图:

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

适用性:

必须保存一个对象在某一个时刻的(部分)状态, 这样以后需要时它才能恢复到先前的状态。

如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。

代码示例

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-'''
Memento
'''import copydef Memento(obj, deep=False):state = (copy.copy, copy.deepcopy)[bool(deep)](obj.__dict__)def Restore():obj.__dict__.clear()obj.__dict__.update(state)return Restoreclass Transaction:"""A transaction guard. This is really justsyntactic suggar arount a memento closure."""deep = Falsedef __init__(self, *targets):self.targets = targetsself.Commit()def Commit(self):self.states = [Memento(target, self.deep) for target in self.targets]def Rollback(self):for st in self.states:st()class transactional(object):"""Adds transactional semantics to methods. Methods decorated  with@transactional will rollback to entry state upon exceptions."""def __init__(self, method):self.method = methoddef __get__(self, obj, T):def transaction(*args, **kwargs):state = Memento(obj)try:return self.method(obj, *args, **kwargs)except:state()raisereturn transactionclass NumObj(object):def __init__(self, value):self.value = valuedef __repr__(self):return '<%s: %r>' % (self.__class__.__name__, self.value)def Increment(self):self.value += 1@transactionaldef DoStuff(self):self.value = 1111  # <- invalid valueself.Increment()  # <- will fail and rollbackif __name__ == '__main__':n = NumObj(-1)print(n)t = Transaction(n)try:for i in range(3):n.Increment()print(n)t.Commit()print('-- commited')for i in range(3):n.Increment()print(n)n.value += 'x'  # will failprint(n)except:t.Rollback()print('-- rolled back')print(n)print('-- now doing stuff ...')try:n.DoStuff()except:print('-> doing stuff failed!')import tracebacktraceback.print_exc(0)passprint(n)

执行结果

        21. 迭代器模式(Iterator) 

 

意图:

提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。

适用性:

访问一个聚合对象的内容而无需暴露它的内部表示。

支持对聚合对象的多种遍历。

为遍历不同的聚合结构提供一个统一的接口(即, 支持多态迭代)。

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-'''
Interator
'''def count_to(count):"""Counts by word numbers, up to a maximum of five"""numbers = ["one", "two", "three", "four", "five"]# enumerate() returns a tuple containing a count (from start which# defaults to 0) and the values obtained from iterating over sequencefor pos, number in zip(range(count), numbers):yield number# Test the generator
count_to_two = count_to(2)
count_to_five = count_to(5)print('Counting to two...')
for number in count_to_two:print(number)print(" ")print('Counting to five...')
for number in count_to_five:print(number)print(" ")

执行结果


        22. 解释器模式(Interpreter)

意图:

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

适用性:

当有一个语言需要解释执行, 并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好:

该文法简单对于复杂的文法, 文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具是更好的选择。它们无需构建抽象语法树即可解释表达式, 这样可以节省空间而且还可能节省时间。

效率不是一个关键问题最高效的解释器通常不是通过直接解释语法分析树实现的, 而是首先将它们转换成另一种形式。例如,正则表达式通常被转换成状态机。但即使在这种情况下, 转换器仍可用解释器模式实现, 该模式仍是有用的。

代码示例:

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-'''
Interpreter
'''class Context:def __init__(self):self.input=""self.output=""class AbstractExpression:def Interpret(self,context):passclass Expression(AbstractExpression):def Interpret(self,context):print("terminal interpret")class NonterminalExpression(AbstractExpression):def Interpret(self,context):print("Nonterminal interpret")if __name__ == "__main__":context= ""c = []c = c + [Expression()]c = c + [NonterminalExpression()]c = c + [Expression()]c = c + [Expression()]for a in c:a.Interpret(context)

  执行结果:

        23.模板方法(Template Method)

意图:

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。TemplateMethod 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

适用性:

一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。

各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。这是Opdyke 和Johnson所描述过的“重分解以一般化”的一个很好的例子[ OJ93 ]。首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。

控制子类扩展。模板方法只在特定点调用“hook ”操作(参见效果一节),这样就只允许在这些点进行扩展

代码示例:

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-'''
Template Method
'''ingredients = "spam eggs apple"
line = '-' * 10# Skeletons
def iter_elements(getter, action):"""Template skeleton that iterates items"""for element in getter():action(element)print(line)def rev_elements(getter, action):"""Template skeleton that iterates items in reverse order"""for element in getter()[::-1]:action(element)print(line)# Getters
def get_list():return ingredients.split()def get_lists():return [list(x) for x in ingredients.split()]# Actions
def print_item(item):print(item)def reverse_item(item):print(item[::-1])# Makes templates
def make_template(skeleton, getter, action):"""Instantiate a template method with getter and action"""def template():skeleton(getter, action)return template# Create our template functions
templates = [make_template(s, g, a)for g in (get_list, get_lists)for a in (print_item, reverse_item)for s in (iter_elements, rev_elements)]# Execute them
for template in templates:template()

简单示例:

__author__ = "Burgess Zheng"
#!/usr/bin/env python
#-*- coding:utf-8 -*-'''
Template Method
'''
# 模板方法模式概述
#        在现实生活中,很多事情都包含几个实现步骤,例如请客吃饭,无论吃什么,一般都包含点单、吃东西、买单等几个步骤,通常情况下这几个步骤的次序是:点单 --> 吃东西 --> 买单。在这三个步骤中,点单和买单大同小异,最大的区别在于第二步——吃什么?吃面条和吃满汉全席可大不相同,如图1所示:
#
# 图1 请客吃饭示意图
#         在软件开发中,有时也会遇到类似的情况,某个方法的实现需要多个步骤(类似“请客”),其中有些步骤是固定的(类似“点单”和“买单”),而有些步骤并不固定,存在可变性(类似“吃东西”)。为了提高代码的复用性和系统的灵活性,可以使用一种称之为模板方法模式的设计模式来对这类情况进行设计,在模板方法模式中,将实现功能的每一个步骤所对应的方法称为基本方法(例如“点单”、“吃东西”和“买单”),而调用这些基本方法同时定义基本方法的执行次序的方法称为模板方法(例如“请客”)。在模板方法模式中,可以将相同的代码放在父类中,例如将模板方法“请客”以及基本方法“点单”和“买单”的实现放在父类中,而对于基本方法“吃东西”,在父类中只做一个声明,将其具体实现放在不同的子类中,在一个子类中提供“吃面条”的实现,而另一个子类提供“吃满汉全席”的实现。通过使用模板方法模式,一方面提高了代码的复用性,另一方面还可以利用面向对象的多态性,在运行时选择一种具体子类,实现完整的“请客”方法,提高系统的灵活性和可扩展性。
#        模板方法模式定义如下:
# 模板方法模式:定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
#
# Template Method Pattern:  Define the skeleton of an algorithm in an  operation, deferring some steps to subclasses. Template Method lets  subclasses redefine certain steps of an algorithm without changing the  algorithm's structure.
#        模板方法模式是一种基于继承的代码复用技术,它是一种类行为型模式。
#        模板方法模式是结构最简单的行为型设计模式,在其结构中只存在父类与子类之间的继承关系。通过使用模板方法模式,可以将一些复杂流程的实现步骤封装在一系列基本方法中,在抽象父类中提供一个称之为模板方法的方法来定义这些基本方法的执行次序,而通过其子类来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果。模板方法模式提供了一个模板方法来定义算法框架,而某些具体步骤的实现可以在其子类中完成。
#class Register(object):'''用户注册接口'''def register(self):passdef login(self):passdef auth(self):self.register()self.login()class RegisterByQQ(Register):'''qq注册'''def register(self):print("---用qq注册-----")def login(self):print('----用qq登录-----')class RegisterByWeiChat(Register):'''微信注册'''def register(self):print("---用微信注册-----")def login(self):print('----用微信登录-----')if __name__ == "__main__":register1 = RegisterByQQ()register1.login()register2 = RegisterByWeiChat()register2.login()

执行结果:

目录篇: python相关目录篇 点击跳转​​​​​​​

Python之23种设计模式相关推荐

  1. python实现23种设计模式

    本文源码寄方于github:https://github.com/w392807287/Design_pattern_of_python 参考文献: <大话设计模式>--吴强 <Py ...

  2. Python的23种设计模式(完整版带源码实例)

    作者:虚坏叔叔 博客:https://xuhss.com 早餐店不会开到晚上,想吃的人早就来了!

  3. python 设计模式 23种_python实现23种设计模式

    本文源码寄方于github:https://github.com/w392807287/Design_pattern_of_python 参考文献: <大话设计模式>--吴强 <Py ...

  4. 23种设计模式介绍(Python示例讲解)

    文章目录 一.概述 二.设计模式七种原则 三.设计模式示例讲解 1)创建型模式 1.工厂模式(Factory Method) [1]简单工厂模式(不属于GOF设计模式之一) [2]工厂方法模式 2.抽 ...

  5. java 的23种设计模式 之单身狗和隔壁老王的故事

    2019独角兽企业重金招聘Python工程师标准>>> 觉得代码写的别扭了,回头翻翻java 的23种设计模式. today,额,这么晚了,困了.就弄个最简单的单例模式吧. 单例模式 ...

  6. 23种设计模式(1):单例模式

    2019独角兽企业重金招聘Python工程师标准>>> 定义:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 类型:创建类模式 类图: 类图知识点: 1.类图分为三 ...

  7. 经典:从追MM谈Java的23种设计模式

    2019独角兽企业重金招聘Python工程师标准>>> 从追MM谈Java的23种设计模式1.FACTORY-追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然 ...

  8. Java 23 种设计模式精讲

    软件设计的原则 1. 开闭原则 定义:软件实体应当对扩展开放,对修改关闭. 2. 里氏替换原则 定义:继承必须保证超类所拥有的性质在子类中仍然成立.即子类在继承父类时,除了添加新的方法来新增功能外,尽 ...

  9. 渣男 23 式 | 23 种设计模式的通俗解释,看完秒懂

    点上方"菜鸟学Python",选择"星标"共460篇原创干货,第一时间送达 来源:http://zhuanlan.zhihu.com/p/100746724 设 ...

最新文章

  1. 比较两个ListT是否相同
  2. 修改grub2安装双系统的windows引导
  3. 手写java数据库连接池,自定义实现数据库连接池,兼容springboot
  4. Kafka入门经典教程【转】
  5. BZOJ4568 : [Scoi2016]幸运数字
  6. CVTE2016校招试题摘选
  7. vue component created没有触发_面试!面试!面试!vue常见面试题。
  8. 模块设计之“模块”与“模块化”
  9. 计算机组成原理中的直接映像,计算机组成原理cache存储器的直接映像与变换.doc...
  10. 《DOM编程艺术》中CSS—DOM的总结(一)
  11. 变种WannaCry
  12. 海外旅游最常用的100句英语口语
  13. 1038: 绝对值最大
  14. python test suite什么意思_如何:在python中设置testsuite
  15. Android源码-高质量开发库
  16. 项目OA之资源结构图
  17. Freeswitch 默认配置
  18. vue3使用箭头函数导入异步组件报错Invalid VNode type: undefined的解决方案
  19. 我的世界java骷髅马_我的世界中国版骷髅马怎么获得 骷髅马召唤驯服指令
  20. 虚幻4混合空间动画蓝图

热门文章

  1. 教你如何打开Centos7的可视化-磁盘使用情况分析-界面
  2. 百度云盘 破解上传限制4G(利用种子)
  3. 制作excle报盘模板
  4. 皮卡丘(pikachu)XXE
  5. 从大厂出来的几个产品朋友,现如今怎么样了?
  6. matlab画图常见问题,matlab常见问题集
  7. Python中的对象实例化过程 用python解密__new__
  8. markdown(Latex)连乘符号
  9. c语言 linux系统 delay,Linux下实现秒级定时任务的两种方案
  10. HIVE:窗口函数,用sql语句查询MySQL安装路径和版本