Python、设计原则和设计模式

前言

程序的目标:高内聚 低耦合

有哪些设计原则

设计原则是「高内聚、低耦合」的具体落地。

  • 单一职责原则要求在软件系统开发、设计中,一个类只负责一个功能领域的相关职责。
  • 开放封闭原则要求一个软件应该对扩展开放,对修改封闭,即在不修改源代码的情况下,完成系统功能的扩展。
  • 里式替换原则决定了子类可以赋值给父类。
  • 依赖倒置原则要求抽象不应该依赖于细节,细节应该依赖于抽象。要面向接口编程,不要面向实现编程。
  • 迪米特原则要求一个对象尽可能少的与其他对象发生相互作用。
  • 接口分离原则要求客户端不应该依赖那些他不需要的接口,即将一些大的接口细化成一些小的接口供客户端使用。
  • 合成复用原则要求我们尽量使用对象的组合,而非继承来达到复用的目标。

什么是设计模式

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

为什么要有设计模式

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

有那些设计模式

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

创建类设计模式(5种)
单例模式、工厂模式(简单工厂模式、抽象工厂模式)、建造者模式、原型模式

结构类设计模式(7种)
代理模式、装饰器模式、适配器模式、门面模式、组合模式、享元模式、桥梁模式

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

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

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

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

设计模式

1 单例模式

单例模式的定义

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

单例模式的示例

总线是计算机各种功能部件或者设备之间传送数据、控制信号等信息的公共通信解决方案之一。
现假设有如下场景:某中央处理器(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.namedef setName(self, name):self.name = namedef run(self):self.my_bus = Bus()print('id bus', id(self.my_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()print('id my_entity', id(my_entity))my_entity.setName("Entity_"+str(i))my_entity.start()

运行结果如下:

Entity 0 begin to run...
id my_entity 1435060096832
id bus 1435061409392
Entity 1 begin to run...
id my_entity 1435061409440
id bus 1435061409392
Entity 2 begin to run...
id my_entity 1435061410064
id bus 1435061409392
Sending Signal Data... Entity_0
Sending Signal Data... Entity_1
Sending Signal Data... Entity_2

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

单例模式的优点

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

单例模式的缺点

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

单例模式的应用举例

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

简单工厂模式

工厂模式是最常用的一类创建型设计模式,通常我们所说的工厂模式是指工厂方法模式,它也是使用频率最高的工厂模式。
简单工厂模式是工厂方法模式的“小弟”,它不属于GoF 23种设计模式,但在软件开发中应用广泛,通常将它作为学习其他工厂模式的入门。
此外,工厂方法模式还有一位“大哥”——抽象工厂模式。这三种工厂模式各具特色,难度也逐个加大,在软件开发中它们都得到了广泛的应用,成为面向对象软件中常用的创建对象的工具。

简单工厂模式的定义

简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例(具体产品对象类-比如猫、狗、鸟等),被创建的实例通常都具有共同的父类(抽象产品对象类-比如动物)。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式。
在使用简单工厂模式时,首先需要对产品类进行重构,不能设计一个包罗万象的产品类,而需根据实际情况设计一个产品层次结构,将所有产品类公共的代码移至抽象产品类,并在抽象产品类中声明一些抽象方法,以供不同的具体产品类来实现。

简单工厂模式的示例

代码中抽象了一个公共类Animal抽象dog、cat公共的方法、两个具体类dog、cat实现Animal以及一个工厂类animalFactory控制具体类的生成。


# 抽象产品类
class Animal():name = ""weight = 0.0type = "Animal"def get_weight(self):return self.weightdef set_weight(self, weight):self.price = weightdef get_name(self):return self.name# 具体产品类
class dog(Animal):def __init__(self):self.name = "dog"self.weight = 40.0# 具体产品类
class cat(Animal):def __init__(self):self.name = "cat"self.weight = 5.0# 简单工厂类
class animalFactory():def create(self, animal):if animal == 'dog':animalIns = dog()elif animal == 'cat':animalIns = cat()return animalInsif __name__ == "__main__":animal_factory = animalFactory()dog = animal_factory.create("dog")print(dog.get_name(), dog.get_weight()) # dog 40.0

简单工厂模式的优点

(1) 工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的职责,而仅仅“消费”产品,简单工厂模式实现了对象创建和使用的分离。
(2) 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以在一定程度减少使用者的记忆量。
(3) 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

简单工厂模式的缺点

(1) 由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响。
(2) 使用简单工厂模式势必会增加系统中类的个数(引入了新的工厂类),增加了系统的复杂度和理解难度。
(3) 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,违背了开闭原则。在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
(4) 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

简单工厂模式的适用场景

(1) 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
(2) 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。

工厂模式

工厂模式的定义

工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式(Factory Pattern),又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。
与简单工厂模式相比,工厂方法模式最重要的区别是引入了抽象工厂角色,抽象工厂可以是接口,也可以是抽象类或者具体类。

工厂模式的示例

代码中抽象了一个公共类Animal抽象dog、cat公共的方法、两个具体类dog、cat实现Animal以及一个工厂类animalFactory控制具体类的生成。


# 抽象产品类
class Animal():name = ""weight = 0.0type = "Animal"def get_weight(self):return self.weightdef set_weight(self, weight):self.price = weightdef get_name(self):return self.name# 具体产品类
class dog(Animal):def __init__(self):self.name = "dog"self.weight = 40.0# 具体产品类
class cat(Animal):def __init__(self):self.name = "cat"self.weight = 5.0# 抽象工厂类
class animalFactory():def create(self):pass# 具体工厂类
class DogFactory(animalFactory):def create(self):return dog()# 具体工厂类
class CatFactory(animalFactory):def create(self):return cat()if __name__ == "__main__":DOG = DogFactory()dog = DOG.create(dog)print(dog.get_name(), dog.get_weight())  # dog 40.0

工厂模式的优点

(1) 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。

(2) 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够让工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,就正是因为所有的具体工厂类都具有同一抽象父类。

(3) 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。

工厂模式的缺点

(1) 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。

(2) 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。

工厂模式的适用场景

(1) 客户端不知道它所需要的对象的类。在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建,可将具体工厂类的类名存储在配置文件或数据库中。

(2) 抽象工厂类通过其子类来指定创建哪个对象。在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。

抽象工厂模式

我们先引入两个概念:

(1) 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。

(2) 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中,海尔电视机、海尔电冰箱构成了一个产品族。
抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形式。抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、更有效率。

抽象工厂模式的定义

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式。
在抽象工厂中声明了多个工厂方法,用于创建不同类型的产品,抽象工厂可以是接口,也可以是抽象类或者具体类

抽象工厂模式的示例

我的这个示例代码可能有点难懂 可以参考参考链接4和5

# 抽象产品类
class Animal():name = ""weight = 0.0type = "Animal"def get_weight(self):return self.weightdef set_weight(self, weight):self.price = weightdef get_name(self):return self.name# 具体产品类
class dog(Animal):def __init__(self):self.name = "dog"self.weight = 40.0# 具体产品类
class cat(Animal):def __init__(self):self.name = "cat"self.weight = 5.0# 抽象产品类
class Animal1():name = ""weight = 0.0type = "Animal1"def get_weight(self):return self.weightdef set_weight(self, weight):self.price = weightdef get_name(self):return self.name# 具体产品类
class dog1(Animal1):def __init__(self):self.name = "dog1"self.weight = 410.0# 具体产品类
class cat1(Animal1):def __init__(self):self.name = "cat1"self.weight = 51.0# 抽象工厂类
class animalFactory():def create_dog(self):passdef create_cat(self):pass# 具体工厂类
class Factory(animalFactory):def create_dog(self):animalIns = dog()return animalInsdef create_cat(self):animalIns = cat()return animalIns# 具体工厂类
class Factory1(animalFactory):def create_dog(self):animalIns = dog1()return animalInsdef create_cat(self):animalIns = cat1()return animalInsif __name__ == "__main__":DOG = Factory1()dog = DOG.create_cat()print(dog.get_name(), dog.get_weight())  # dog 40.0

抽象工厂模式的优点

(1) 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。

(2) 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。

(3) 增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。

抽象工厂模式的缺点

增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。

抽象工厂模式的适用场景

(1) 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是很重要的,用户无须关心对象的创建过程,将对象的创建和使用解耦。

(2) 系统中有多于一个的产品族,而每次只使用其中某一产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。

(3) 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。同一个产品族中的产品可以是没有任何关系的对象,但是它们都具有一些共同的约束,如同一操作系统下的按钮和文本框,按钮与文本框之间没有直接关系,但它们都是属于某一操作系统的,此时具有一个共同的约束条件:操作系统的类型。

(4) 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。

工厂模式总结

简单工厂 : 用来生产同一等级结构中的任意产品。(不支持拓展增加产品)

工厂方法 :用来生产同一等级结构中的固定产品。(支持拓展增加产品)

抽象工厂 :用来生产不同产品族的全部产品。(支持拓展增加产品;支持增加产品族)

简单工厂的适用场合:只有伦敦工厂(只有这一个等级),并且这个工厂只生产三种类型的pizza:chesse,pepper,greak(固定产品)。

工厂方法的适用场合:现在不光有伦敦工厂,还增设了纽约工厂(仍然是同一等级结构,但是支持了产品的拓展),这两个工厂依然只生产三种类型的pizza:chesse,pepper,greak(固定产品)。

抽象工厂的适用场合:不光增设了纽约工厂(仍然是同一等级结构,但是支持了产品的拓展),这两个工厂还增加了一种新的类型的pizza:chinese pizza(增加产品族)。

原型设计模式

浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。

深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。clone明显是深复制,clone出来的对象是是不能去影响原型对象的

原型设计模式的定义

原型模式(Prototype Pattern):使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
简单地理解,其实就是当需要创建一个指定的对象时,我们刚好有一个这样的对象,但是又不能直接使用,我会clone一个一毛一样的新对象来使用;基本上这就是原型模式。关键字:Clone。

原型设计模式的示例

from collections import OrderedDict
import copyclass Book:# 具体书本类def __init__(self, name, authors, price, **rest):self.name = nameself.authors = authorsself.price = priceself.__dict__.update(rest)def __str__(self):mylist = []ordered = OrderedDict(sorted(self.__dict__.items()))for i in ordered.keys():mylist.append('{}: {}'.format(i, ordered[i]))if i == "price":mylist.append('$')mylist.append('\n')return ''.join(mylist)class Prototype:# 抽象copy类def __init__(self):self.objects = dict()def register(self, identifier, obj):self.objects[identifier] = objdef unregister(self, identifier):del self.objects[identifier]def clone(self, identifier, **attr):found = self.objects.get(identifier)if not found:raise ValueError('Incorrect object identifier {}'.format(identifier))obj = copy.deepcopy(found)obj.__dict__.update(attr)return objdef main():# 新增b1b1 = Book('The C Programming Language', ('Brian W. Kernighan', 'Dennis M.Richie'),price=118, publisher='Prentice Hall', length=228,publication_date='1978-02-22',tags=('C', 'programming', 'algorithms', 'data structures'))prototype = Prototype()cid = 'k&r-first'prototype.register(cid, b1)# 复制b2 = prototype.clone(cid, name='The C Programming Language(ANSI)', price=48.99,length=274, publication_date='1988-04-01', edition=2)for i in (b1, b2):print(i)print("ID b1 : {} , ID b2 : {}".format(id(b1), id(b2)))if __name__ == '__main__':main()

原型设计模式的优点

(1) 当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,通过复制一个已有实例可以提高新实例的创建效率。

(2) 扩展性较好,由于在原型模式中提供了抽象原型类,在客户端可以针对抽象原型类进行编程,而将具体原型类写在配置文件中,增加或减少产品类对原有系统都没有任何影响。

(3) 原型模式提供了简化的创建结构,工厂方法模式常常需要有一个与产品类等级结构相同的工厂等级结构,而原型模式就不需要这样,原型模式中产品的复制是通过封装在原型类中的克隆方法实现的,无须专门的工厂类来创建产品。

(4) 可以使用深克隆的方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用(如恢复到某一历史状态),可辅助实现撤销操作。

原型设计模式的缺点

(1) 需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进行改造时,需要修改源代码,违背了“开闭原则”。

(2) 在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来可能会比较麻烦。

原型设计模式的适用场景

(1) 创建新对象成本较大(如初始化需要占用较长的时间,占用太多的CPU资源或网络资源),新的对象可以通过原型模式对已有对象进行复制来获得,如果是相似对象,则可以对其成员变量稍作修改。

(2) 如果系统要保存对象的状态,而对象的状态变化很小,或者对象本身占用内存较少时,可以使用原型模式配合备忘录模式来实现。

(3) 需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态,通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便。

建造者模式

建造者模式的定义

建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

建造者模式的示例

class Burger():name = ""price = 0.0def getPrice(self):return self.pricedef setPrice(self, price):self.price = pricedef getName(self):return self.nameclass cheeseBurger(Burger):def __init__(self):self.name = "cheese burger"self.price = 10.0class spicyChickenBurger(Burger):def __init__(self):self.name = "spicy chicken burger"self.price = 15.0class Snack():name = ""price = 0.0type = "SNACK"def getPrice(self):return self.pricedef setPrice(self, price):self.price = pricedef getName(self):return self.nameclass chips(Snack):def __init__(self):self.name = "chips"self.price = 6.0class chickenWings(Snack):def __init__(self):self.name = "chicken wings"self.price = 12.0class Beverage():name = ""price = 0.0type = "BEVERAGE"def getPrice(self):return self.pricedef setPrice(self, price):self.price = pricedef getName(self):return self.nameclass coke(Beverage):def __init__(self):self.name = "coke"self.price = 4.0class milk(Beverage):def __init__(self):self.name = "milk"self.price = 5.0class orderBuilder():# 抽象建造类bBurger = ""bSnack = ""bBeverage = ""def addBurger(self, xBurger):self.bBurger = xBurgerdef addSnack(self, xSnack):self.bSnack = xSnackdef addBeverage(self, xBeverage):self.bBeverage = xBeveragedef build(self):return order(self)class orderDirector():# 指挥类order_builder = ""def __init__(self, order_builder):self.order_builder = order_builderdef 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()class order():# 具体建造类burger = ""snack = ""beverage = ""def __init__(self, orderBuilder):self.burger = orderBuilder.bBurgerself.snack = orderBuilder.bSnackself.beverage = orderBuilder.bBeveragedef show(self):print("Burger:%s" % self.burger.getName())print("Snack:%s" % self.snack.getName())print("Beverage:%s" % self.beverage.getName())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()# 引入指挥者order_director = orderDirector(order_builder=order_builder)order_2 = order_director.createOrder(spicyChickenBurger(), chips(), milk())order_2.show()

建造者模式的优点

(1) 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。

(2) 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。由于指挥者类针对抽象建造者编程,增加新的具体建造者无须修改原有类库的代码,系统扩展方便,符合“开闭原则”

(3) 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。

建造者模式的缺点

(1) 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的限制。

(2) 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加系统的理解难度和运行成本。

建造者模式的适用场景

(1) 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。

(2) 需要生成的产品对象的属性相互依赖,需要指定其生成顺序。

(3) 对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类和客户类中。

(4) 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。

参考文章

  1. https://blog.csdn.net/m0_67155975/article/details/123452908
  2. https://blog.csdn.net/A1342772/article/details/91349142
  3. https://blog.csdn.net/LoveLion/article/details/17517213
  4. https://blog.csdn.net/kobe_okok/article/details/119790437
  5. https://blog.csdn.net/ponder008/article/details/6886039
  6. python原型模式 https://blog.csdn.net/u014686399/article/details/125116794

Python、设计原则和设计模式-创建类设计模式相关推荐

  1. 创建类设计模式简洁介绍

    一 闲谈 最近在复习设计模式,很多模式让说名字,可能记不住,但是日常开发中用的挺多的,有时候形成一种习惯.这一轮学习先把模式简化下,以前学什么总讲究完备,好像少了点很重要似的,其实很多时候应用的是基础 ...

  2. 设计模式--创建型设计模式

    一. 设计模式的目的 ​ 编写软件过程中,可能面临来自耦合性.内聚性.可维护性.可扩展性.重用性.灵活性等多方面的挑战,设计模式是为了让程序具有更好的: 代码重用性(即相同的代码,不用多次编写) 可读 ...

  3. java并发编程:设计原则与模式_java编程设计模式一——策略模式

    定义: 策略模式定义了算法族,分别封装起来,让它们之间相互替代.此模式让算法的变化独立于使用算法的客户. 问题描述: 建立一个鸭子Duck的父类,它有很多子类,Duck都会游泳,但是有鸭子会飞,有的鸭 ...

  4. 设计模式——创建型设计模式

    创建型设计模式 争对对象/类创建时的优化 工厂方法模式(了解) 通过定义顶层抽象工厂类,通过继承的方式,针对于每一个产品都提供一个工厂类用于创建. 情况:只适用于简单对象,当我们需要生产许多个产品族的 ...

  5. 设计模式----创建型设计模式(单例模式、工厂方法模式、构建者模式)

    创建型设计模式 单例模式(Singleton Pattern) 单例模式介绍 代码演示 饿汉式(静态常量) 饿汉式(静态代码块) 懒汉式(线程不安全) 懒汉式(线程安全,同步方法) 懒汉式(线程安全, ...

  6. javaScript设计模式-创建型设计模式

    我们大家一听到设计模式就感觉设计模式是一个高端的东西,到底什么是设计模式呢?其实设计模式也就是我们的前辈在写代码的时候遇到的问题,提出的解决方案,为了方便人与人之间的交流,取了个名字,叫做设计模式. ...

  7. python 动态_python实现动态创建类的方法分析

    本文实例讲述了python实现动态创建类的方法.分享给大家供大家参考,具体如下: python作为动态语言,如何在运行时动态创建类呢(python Creating classes dynamical ...

  8. python设计tcp数据包协议类

    一.问题描述 在tcp编程中,最需要解决的就是粘包分包问题.所以,我们需要在每个数据包前面加上数据包的长度用以分割粘连的包. 二.包结构的设计 包的组成:包长度+数据域 包长度:用4个字节存储数据域长 ...

  9. MySQL~索引设计原则:适合创建索引的11种情况、不适合创建索引的7种情况

    文章目录 数据的准备 适合创建索引 不适合创建索引 数据的准备 #1. 数据的准备CREATE DATABASE atguigudb1;USE atguigudb1;#1.创建学生表和课程表 CREA ...

最新文章

  1. C++模板详解——使用篇
  2. php用存储过程插入数据,如何使用php-webservice使用android中的存储过程将数据插入sql数据库[duplicate]...
  3. 用Python实现双端队列
  4. 深入Synchronized和java.util.concurrent.locks.Lock的区别详解
  5. oracle 并行执行脚本,批量执行Oracle脚本
  6. 为什么 MySQL 不推荐使用 join?
  7. MISRA C编程规范标准
  8. 【湖南集训 4.2】正12面体
  9. 从0开发《工程测绘大师》小程序之6°带中央子午线计算篇(八)
  10. 2-4 实变函数之可测函数
  11. Reading Note(4)——面向关系型数据库的哈希连接加速器
  12. 机器学习中的数学原理——随机梯度下降法
  13. 分享一套国产化技术开发JAVA语言,大佬手下留情
  14. 沈剑老师的MySQL军规
  15. 韬韬抢苹果 #普及组#
  16. 很显然,现在元宇宙、web3.0的关注度,早已超过了区块链
  17. 图片格式批量转换,批量处理
  18. 【讨论】读博最多收入的高校是哪个?中国高校硕博补贴大盘点!
  19. 购买服务器并设置Nginx
  20. vert.x+java入门_vertx从入门到精通

热门文章

  1. CSU-1729_齿轮转动
  2. 敷完面膜后要擦水乳吗_敷完面膜后要擦水乳吗
  3. markdown字体大小设置_Markdown 颜色和字体
  4. 关于输入电阻和输出电阻大小的讨论
  5. 展望2025:决定未来经济的12大颠覆技术
  6. Keepalived_vrrp[15699]: (VI_1): ip address associated with VRID 51 not present in MASTER advert : ..
  7. 学校校园学生信息管理系统 毕业设计毕业源码毕业论文开题报告参考(1)功能概要
  8. 熵权TOPSIS法有哪些指标?
  9. 文件下载管理 全套方案
  10. 快速矩阵乘法的研究——中