锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

Python的23种设计模式

时间:2023-02-12 03:30:01 m23系列圆形连接器way系列圆形耦合连接器

文章目录

  • Python设计模式-前言
    • 一 什么是设计模式?
    • 二 为什么要有设计模式?
    • 三 有那些设计模式
        • 创建设计模式(5种)
        • 结构设计模式(7种)
        • 行为设计模式(11种)
    • 四 设计模式与架构、框架之间的关系
        • 1 软件框架与设计模式的关系
        • 2 软件架构与设计模式的关系
  • 1 单例模式
    • 一、总线
    • 二、单例模式
    • 三、单例模式的优点及应用
        • 单例模式的优点
        • 单例模式的应用示例
    • 四、单例模式的缺点
  • 2 工厂相关模式(占两种)
    • 一、快餐点餐系统
    • 二、工厂模式简单,工厂模式抽象
    • 三、工厂模式的优势及应用
    • 四、工厂模式不足
  • 3 建造者模式
    • 一、快餐点餐系统
    • 二、建造者模式
    • 三、建筑模式的优势和使用场景
        • 优点:
        • 使用场景:
    • 四、建筑模式的缺点
  • 4 原型模式
    • 一、图层
    • 二、原型模式
    • 三、原型模式的优点及使用场景
        • 优点:
        • 使用场景:
    • 四、原型模式的缺点
  • 5 代理模式
    • 1.网络服务器配置白名单
    • 二、代理模式
    • 三、代理模式和应用场景的优势
        • 优点:
        • 应用场景:
    • 四、代理模式的缺点
  • 6 装饰器模式
    • 一、快餐点餐系统
    • 二、装饰器模式
    • 三、装饰模式和应用场景的优点
        • 优点:
        • 应用场景:
    • 四、装饰模式的缺点
  • 7 适配器模式
    • 1.外包人员系统兼容
    • 二、适配器模式
    • 三、适配器模式的优点及使用场景
        • 优点:
        • 应用场景:
    • 四、适配器模式的缺点
  • 8 门面模式
    • 一、火警报警器(1)
    • 二、立面模式
    • 三、立面模式的优点及使用场景
        • 优点:
        • 使用场景:
    • 四、门面模式的缺点
  • 9 组合模式
    • 一、公司结构组织
    • 二、组合模式
    • 三、组合模式和使用场景的优点
        • 优点:
        • 使用场景:
    • 四、组合模式的缺点
  • 10 享元模式
    • 一、网上咖啡购买平台
    • 二、享元模式
    • 三、享元模式的优势及使用场景
        • 优点:
        • 使用场景:
    • 四、享元模式的缺点
  • 11 桥梁模式
    • 一、画笔和形状
    • 二、桥梁模式
    • 三、桥梁模式的优点及应用场景
        • 优点:
        • 应用场景:
    • 四、桥梁模式的缺点
  • 12 策略模式
    • 一、客户消息通知
    • 二、战略模式
    • 三、战略模式和应用场景的优势
        • 优点:
        • 应用场景:
    • 四、战略模式的缺点
  • 13 责任链模式
    • 一、请假系统
    • 二、责任链模式
    • 三、责任链模式和应用场景的优势
        • 优点:
        • 应用场景:
    • 四、责任链模式的缺点
  • 14 命令模式
    • 一、酒店点餐系统
    • 二、命令模式
    • 三、命令模式和应用场景的优势
        • 优点:
        • 应用场景:
    • 四、命令模式的缺点
  • 15 中介者模式
    • 一、仓储管理系统
    • 二、中介者模式
    • 三、中介者模式的优点和应用场景
        • 优点:
        • 应用场景:
    • 四、中介者模式的缺点
  • 16 模板模式
    • 一、股票查询客户端
    • 二、模板模式
    • 三、模板模式的优点和应用
        • 优点:
        • 使用场景:
    • 四、模板模式的缺点
  • 17 迭代器模式
    • 一、迭代器与生成器
    • 二、迭代器模式
  • 18 访问者模式
    • 一、药房业务系统
    • 二、访问者模式
    • 三、访问者模式的优点和应用场景
        • 优点:
        • 应用场景:
    • 四、访问者模式的缺点
  • 19 观察者模式
    • 一、火警报警器
    • 二、观察者模式
    • 三、观察者模式的优点和应用场景
        • 优点:
        • 应用场景:
    • 四、观察者模式的缺点
  • 20 解释器模式
    • 一、模拟吉他
    • 二、解释器模式
    • 三、解释器模式的优点和应用场景
        • 优点:
        • 应用场景:
    • 四、解释器模式的缺点
  • 21 备忘录模式
    • 一、游戏进度保存
    • 二、备忘录模式
    • 三、备忘录模式应用场景
  • 22 状态模式
    • 一、电梯控制器
      • 二、状态模式
    • 三、状态模式的优点和应用场景
        • 优点:
        • 应用场景:
    • 四、状态模式的缺点
  • 23 设计原则
    • 一 六大设计原则
        • 1、单一职责原则
        • 2、里氏替换原则
        • 3、依赖倒置原则
        • 4、接口隔离原则
        • 5、迪米特法则(最少知识原则)
        • 6、开闭原则
    • 二 遵循设计原则的好处
    • 三、设计原则与设计模式
        • 1、创建类设计模式与设计原则
        • 2、结构类设计模式与设计原则
        • 3、行为类设计模式与设计原则

Python与设计模式–前言

一 什么是设计模式

设计模式是面对各种问题进行提炼和抽象而形成的解决方案。这些设计方案是前人不断试验,考虑了封装性、复用性、效率、可修改、可移植等各种因素的高度总结。它不限于一种特定的语言,它是一种解决问题的思想和方法

二 为什么要有设计模式

公司人事会有变动,程序员也会成长。不管是哪种情况,代码非常有可能会被移交,即代码的编写者和维护者很有可能会是不同的人。那么代码的可读性就显得非常重要了。由于高级语言的出现,让机器读懂你的意图已经不是最主要的“矛盾”,而让人读懂你的意图才是最重要。按照设计模式编写的代码,其可读性也会大大提升,利于团队项目的继承和扩展

三 有那些设计模式

设计模式可以分为三个大类:创建类设计模式、结构类设计模式、行为类设计模式

创建类设计模式(5种)

单例模式、工厂模式(简单工厂模式、抽象工厂模式)、建造者模式、原型模式

结构类设计模式(7种)

代理模式、装饰器模式、适配器模式、门面模式、组合模式、享元模式、桥梁模式

行为类设计模式(11种)

策略模式、责任链模式、命令模式、中介者模式、模板模式、迭代器模式、访问者模式、观察者模式、解释器模式、备忘录模式、状态模式
设计模式也衍生出了很多的新的种类,不局限于这23种

四 设计模式与架构,框架的关系

1 软件框架与设计模式的关系

软件框架随着软件工程的发展而出现,所谓的软件框架,是提取了特定领域的软件的共性部分所形成的软件体系,它并不是一个成熟的软件,而更像是一个“半成品”,程序员在框架之上,可以很方便地某些特定领域实现又快又可靠的二次开发。
设计模式软件框架在软件设计中是两个不同的研究领域:
A、设计模式如前边的定义所讲,它指的是针对一类问题的解决方法,一个设计模式可应用于不同的框架和被不同的语言所实现;而框架则是一个应用的体系结构,是一种或多种设计模式和代码的混合体;
B、设计模式相较于框架更容易移植,并且可以用各种语言实现,而软件框架则受限于领域大环境。虽然设计模式和软件框架有很多不同,但在某些方面他们二者是统一的,即重视软件复用,提高开发效率。

2 软件架构与设计模式的关系

软件架构是个比较大的概念,架构要考虑软件的整体结构、层次划分以及不同部分间的协作和交互等,架构的着眼点偏整体。
相比之下,框架和设计模式的范围则具体很多,框架着眼于领域内的解决方法,而设计模式则针对一类问题的解决方案和设计思路。
总体来说,软件架构可以由不同的框架和不同的设计模式,再加上特定的构件组合来实现;框架可以根据设计模式结合特定编程语言和环境来实现。设计模式就是解决单一问题的设计思路和解决方法。

1 单例模式

一、总线

总线是计算机各种功能部件或者设备之间传送数据、控制信号等信息的公共通信解决方案之一。
现假设有如下场景:某中央处理器(CPU)通过某种协议总线与一个信号灯相连,信号灯有64种颜色可以设置,中央处理器上运行着三个线程,都可以对这个信号灯进行控制,并且可以独立设置该信号灯的颜色。
抽象掉协议细节(用打印表示),如何实现线程对信号等的控制逻辑。
加线程
进行控制,无疑是最先想到的方法,但各个线程对锁的控制,无疑加大了模块之间的耦合。下面,我们就用设计模式中的单例模式,来解决这个问题。
什么是单例模式?单例模式是指:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
具体到此例中,总线对象,就是一个单例,它仅有一个实例,各个线程对总线的访问只有一个全局访问点,即惟一的实例。
Python代码如下:

# encoding=utf8
import threading
import time
# 这里使用方法__new__来实现单例模式


class Singleton(object):  # 抽象单例
    def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kw)
        return cls._instance
# 总线


class Bus(Singleton):
    lock = threading.RLock()

    def sendData(self, data):
        self.lock.acquire()
        time.sleep(3)
        print("Sending Signal Data...", data)
        self.lock.release()
# 线程对象,为更加说明单例的含义,这里将Bus对象实例化写在了run里


class VisitEntity(threading.Thread):
    my_bus = ""
    name = ""

    def getName(self):
        return self.name

    def setName(self, name):
        self.name = name

    def run(self):
        self.my_bus = Bus()
        self.my_bus.sendData(self.name)


if __name__ == "__main__":
    for i in range(3):
        print("Entity %d begin to run..." % i)
        my_entity = VisitEntity()
        my_entity.setName("Entity_"+str(i))
        my_entity.start()

运行结果如下:

Entity 0 begin to run...
Entity 1 begin to run...
Entity 2 begin to run...
Sending Signal Data... Entity_0
Sending Signal Data... Entity_1
Sending Signal Data... Entity_2

在程序运行过程中,三个线程同时运行(运行结果的前三行先很快打印出来),而后分别占用总线资源(后三行每隔3秒打印一行)。虽然看上去总线Bus被实例化了三次,但实际上在内存里只有一个实例。

二、单例模式

单例模式是所有设计模式中比较简单的一类,其定义如下:Ensure a class has only one instance, and provide a global point of access to it.(保证某一个类只有一个实例,而且在全局只有一个访问点)

三、单例模式的优点和应用

单例模式的优点

1、由于单例模式要求在全局内只有一个实例,因而可以节省比较多的内存空间;
2、全局只有一个接入点,可以更好地进行数据同步控制,避免多重占用;3、单例可长驻内存,减少系统开销。

单例模式的应用举例

1、生成全局惟一的序列号;
2、访问全局复用的惟一资源,如磁盘、总线等;
3、单个对象占用的资源过多,如数据库等;
4、系统全局统一管理,如Windows下的Task Manager;
5、网站计数器。

四、单例模式的缺点

1、单例模式的扩展是比较困难的;
2、赋于了单例以太多的职责,某种程度上违反单一职责原则(六大原则后面会讲到);
3、单例模式是并发协作软件模块中需要最先完成的,因而其不利于测试;4、单例模式在某种情况下会导致“资源瓶颈”。

2 工厂类相关模式(占了两种)

一、快餐点餐系统

想必大家一定见过类似于麦当劳自助点餐台一类的点餐系统吧。在一个大的触摸显示屏上,有三类可以选择的上餐品:汉堡等主餐、小食、饮料。当我们选择好自己需要的食物,支付完成后,订单就生成了。下面,我们用今天的主角–工厂模式–来生成这些食物的逻辑主体。首先,来看主餐的生成(仅以两种汉堡为例)。

class Burger():
    name = ""
    price = 0.0

    def getPrice(self):
        return self.price

    def setPrice(self, price):
        self.price = price

    def getName(self):
        return self.name


class cheeseBurger(Burger):
    def __init__(self):
        self.name = "cheese burger"
        self.price = 10.0


class spicyChickenBurger(Burger):
    def __init__(self):
        self.name = "spicy chicken burger"
        self.price = 15.0

其次,是小食。(内容基本一致)

class Snack():
    name = ""
    price = 0.0
    type = "SNACK"

    def getPrice(self):
        return self.price

    def setPrice(self, price):
        self.price = price

    def getName(self):
        return self.name


class chips(Snack):
    def __init__(self):
        self.name = "chips"
        self.price = 6.0


class chickenWings(Snack):
    def __init__(self):
        self.name = "chicken wings"
        self.price = 12.0

最后,是饮料。

class Beverage():
    name = ""
    price = 0.0
    type = "BEVERAGE"

    def getPrice(self):
        return self.price

    def setPrice(self, price):
        self.price = price

    def getName(self):
        return self.name


class coke(Beverage):
    def __init__(self):
        self.name = "coke"
        self.price = 4.0


class milk(Beverage):
    def __init__(self):
        self.name = "milk"
        self.price = 5.0

以上的Burger,Snack,Beverage,都可以认为是该快餐店的产品,由于只提供了抽象方法,我们把它们叫抽象产品类,而cheese burger等6个由抽象产品类衍生出的子类,叫作具体产品类。接下来,“工厂”就要出现了。

class foodFactory():
    type = ""

    def createFood(self, foodClass):
        print self.type, " factory produce a instance."
        foodIns = foodClass()
        return foodIns


class burgerFactory(foodFactory):
    def __init__(self):
        self.type = "BURGER"


class snackFactory(foodFactory):
    def __init__(self):
        self.type = "SNACK"


class beverageFactory(foodFactory):
    def __init__(self):
        self.type = "BEVERAGE"

同样,foodFactory为抽象的工厂类,而burgerFactory,snackFactory,beverageFactory为具体的工厂类。在业务场景中,工厂模式是如何“生产”产品的呢?

if __name__ == "__main__":
    burger_factory = burgerFactory()
    snack_factorry = snackFactory()
    beverage_factory = beverageFactory()
    cheese_burger = burger_factory.createFood(cheeseBurger)
    print (cheese_burger.getName(), cheese_burger.getPrice())
    chicken_wings = snack_factorry.createFood(chickenWings)
    print (chicken_wings.getName(), chicken_wings.getPrice())
    coke_drink = beverage_factory.createFood(coke)
    print (coke_drink.getName(), coke_drink.getPrice())

可见,业务中先生成了工厂,然后用工厂中的createFood方法和对应的参数直接生成产品实例。打印结果如下:BURGER factory produce a instance.cheese burger 10.0SNACK factory produce a instance.chicken wings 12.0BEVERAGE factory produce a instance.coke 4.0

二、工厂模式、简单工厂模式、抽象工厂模式

工厂模式的定义如下:定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类。其通用类图如下。其产品类定义产品的公共属性和接口,工厂类定义产品实例化的“方式”。在上述例子中,工厂在使用前必须实例化。如果,把工厂加个类方法,写成如下形式:

class simpleFoodFactory():
    @classmethod
    def createFood(cls,foodClass):
        print "Simple factory produce a instance."
        foodIns = foodClass()
        return foodIns

在场景中写成如下形式:spicy_chicken_burger=simpleFoodFactory.createFood(spicyChickenBurger)这样,省去了将工厂实例化的过程。这种模式就叫做简单工厂模式。还是在上述例子中,createFood方法中必须传入foodClass才可以指定生成的food实例种类,如果,将每一个细致的产品都建立对应的工厂(如cheeseBurger建立对应一个cheeseBurgerFactory),这样,生成食物时,foodClass也不必指定。事实上,此时,burgerFactory就是具体食物工厂的一层抽象。这种模式,就是抽象工厂模式。

三、工厂模式的优点和应用

工厂模式、抽象工厂模式的优点:
1、工厂模式巨有非常好的封装性,代码结构清晰;在抽象工厂模式中,其结构还可以随着需要进行更深或者更浅的抽象层级调整,非常灵活;
2、屏蔽产品类,使产品的被使用业务场景和产品的功能细节可以分而开发进行,是比较典型的解耦框架。
工厂模式、抽象工厂模式的使用场景:
1、当系统实例要求比较灵活和可扩展时,可以考虑工厂模式或者抽象工厂模式实现。比如,在通信系统中,高层通信协议会很多样化,同时,上层协议依赖于下层协议,那么就可以对应建立对应层级的抽象工厂,根据不同的“产品需求”去生产定制的实例。

四、工厂类模式的不足

1、工厂模式相对于直接生成实例过程要复杂一些,所以,在小项目中,可以不使用工厂模式;
2、抽象工厂模式中,产品类的扩展比较麻烦。毕竟,每一个工厂对应每一类产品,产品扩展,就意味着相应的抽象工厂也要扩展

3 建造者模式

一、快餐点餐系统

今天的例子,还是上一次谈到的快餐点餐系统。只不过,今天我们从订单的角度来构造这个系统。最先还是有请上次的主角们:主餐:

class Burger():
    name=""
    price=0.0
    def getPrice(self):
        return self.price
    def setPrice(self,price):
        self.price=price
    def getName(self):
        return self.name
class cheeseBurger(Burger):
    def __init__(self):
        self.name="cheese burger"
        self.price=10.0
class spicyChickenBurger(Burger):
    def __init__(self):
        self.name="spicy chicken burger"
        self.price=15.0

小食:

class Snack():
    name = ""
    price = 0.0
    type = "SNACK"
    def getPrice(self):
        return self.price
    def setPrice(self, price):
        self.price = price
    def getName(self):
        return self.name


class chips(Snack):
    def __init__(self):
        self.name = "chips"
        self.price = 6.0


class chickenWings(Snack):
    def __init__(self):
        self.name = "chicken wings"
        self.price = 12.0

饮料:

class Beverage():
    name = ""
    price = 0.0
    type = "BEVERAGE"
    def getPrice(self):
        return self.price
    def setPrice(self, price):
        self.price = price
    def getName(self):
        return self.name


class coke(Beverage):
    def __init__(self):
        self.name = "coke"
        self.price = 4.0


class milk(Beverage):
    def __init__(self):
        self.name = "milk"
        self.price = 5.0

最终,我们是要建造一个订单,因而,需要一个订单类。假设,一个订单,包括一份主食,一份小食,一种饮料。(省去一些异常判断)

class order():
    burger=""
    snack=""
    beverage=""
    def __init__(self,orderBuilder):
        self.burger=orderBuilder.bBurger
        self.snack=orderBuilder.bSnack
        self.beverage=orderBuilder.bBeverage
    def show(self):
        print "Burger:%s"%self.burger.getName()
        print "Snack:%s"%self.snack.getName()
        print "Beverage:%s"%self.beverage.getName()

**代码中的orderBuilder是什么鬼?这个orderBuilder就是建造者模式中所谓的“建造者”了,先不要问为什么不在order类中把所有内容都填上,而非要用builder去创建。接着往下看。**orderBuilder的实现如下

class orderBuilder():
    bBurger=""
    bSnack=""
    bBeverage=""
    def addBurger(self,xBurger):
        self.bBurger=xBurger
    def addSnack(self,xSnack):
        self.bSnack=xSnack
    def addBeverage(self,xBeverage):
        self.bBeverage=xBeverage
    def build(self):
        return order(self)

在场景中如下去实现订单的生成:

if  __name__=="__main__":
    order_builder=orderBuilder()
    order_builder.addBurger(spicyChickenBurger())
    order_builder.addSnack(chips())
    order_builder.addBeverage(milk())
    order_1=order_builder.build()
    order_1.show()

打印结果如下:Burger:spicy chicken burgerSnack:chipsBeverage:milk

二、建造者模式

建造者模式的定义如下:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式的作用,就是将“构建”和“表示”分离,以达到解耦的作用。在上面订单的构建过程中,如果将order直接通过参数定义好(其构建与表示没有分离),同时在多处进行订单生成,此时需要修改订单内容,则需要一处处去修改,业务风险也就提高了不少。在建造者模式中,还可以加一个Director类,用以安排已有模块的构造步骤。对于在建造者中有比较严格的顺序要求时,该类会有比较大的用处。在上述例子中,Director实现如下:

class orderDirector():
    order_builder=""
    def __init__(self,order_builder):
        self.order_builder=order_builder
    def createOrder(self,burger,snack,beverage):
        self.order_builder.addBurger(burger)
        self.order_builder.addSnack(snack)
        self.order_builder.addBeverage(beverage)
        return self.order_builder.build()

通过createOrder直接代入参数,即可直接生成订单。

三、建造者模式的优点和使用场景

优点:

1、封装性好,用户可以不知道对象的内部构造和细节,就可以直接建造对象;2、系统扩展容易;3、建造者模式易于使用,非常灵活。在构造性的场景中很容易实现“流水线”;4、便于控制细节。

使用场景:

1、目标对象由组件构成的场景中,很适合建造者模式。例如,在一款赛车游戏中,车辆生成时,需要根据级别、环境等,选择轮胎、悬挂、骨架等部件,构造一辆“赛车”;2、在具体的场景中,对象内部接口需要根据不同的参数而调用顺序有所不同时,可以使用建造者模式。例如:一个植物养殖器系统,对于某些不同的植物,浇水、施加肥料的顺序要求可能会不同,因而可以在Director中维护一个类似于队列的结构,在实例化时作为参数代入到具体建造者中。

四、建造者模式的缺点

1、“加工工艺”对用户不透明。(封装的两面性)

4 原型模式

一、图层

大家如果用过类似于Photoshop的平面设计软件,一定都知道图层的概念。图层概念的提出,使得设计、图形修改等操作更加便利。设计师既可以修改和绘制当前图像对象,又可以保留其它图像对象,逻辑清晰,且可以及时得到反馈。本节内容,将以图层为主角

相关文章