当前位置: 首页 > news >正文

【设计模式|上】创建型模式

every blog every motto: You can do more than you think.
https://blog.csdn.net/weixin_39190382?type=blog

0. 前言

设计模式(上):

  • 简单工厂模式
  • 工厂模式
  • 抽象工厂模式
  • 建造者模式
  • 单例模式

1. 正文

1.1 创建型(Creational Patterns)

1.1.1 简单工厂模式(Simple factory)

说明: 非标准的GoF总结设计的23种设计模式之一,可作为工厂模式的需要解决的问题

'''
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()

作用: 定义一个用于创建对象的接口,让子类决定实例化哪一个。
场景:

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

优点: 客户端不需要修改代码。
缺点: 当需要增加新的运算类的时候,不仅需新加运算类,还要修改工厂类,违反了开闭原则

1.1.2 工厂方法模式(Factory Method)

案例1:

'''
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()

核心: ShapeInterfaceFactory(父类 or 基类):提取出所有子类的重复方法代码

案例2:

使用步骤:

  1. 创建抽象工厂类,定义具体工厂的公共接口;
  2. 创建抽象产品类 ,定义具体产品的公共接口;
  3. 创建具体产品类(继承抽象产品类) ,定义生产的具体产品;
  4. 创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
  5. 外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
# 抽象工厂类
class WeChatFactory(object):def create_wechat(self):pass# 具体工厂类A(创建账号A)
class AccountAFactory(WeChatFactory):def create_wechat(self):return AccountA()# 具体工厂类B(创建账号B)
class AccountBFactory(WeChatFactory):def create_wechat(self):return AccountB()# 抽象产品类(微信账号功能)
class WeChat(object):def send_message(self, content):passdef send_image(self, imageid):pass# 具体产品类A(账号A功能)
class AccountA(WeChat):def send_message(self, content):print("使用企业微信账号A推送信息: ", content)def send_image(self, imageid):print("使用企业微信账号A推送图片: ", imageid)# 具体产品类B(账号B功能)
class AccountB(WeChat):def send_message(self, content):print("使用企业微信账号B推送信息: ", content)def send_image(self, imageid):print("使用企业微信账号B推送图片: ", imageid)
​
​
​
if __name__ == "__main__":# 实例化账号Awechat_factory_a = AccountAFactory()# 创建账号A的微信对象wechat1 = wechat_factory_a.create_wechat()# 使用账号A对象发送信息wechat1.send_message(content="haha")wechat1.send_image(imageid="hehe.jpg")# 实例化账号Bwechat_factory_b = AccountBFactory()# 创建账号B的微信对象wechat2 = wechat_factory_b.create_wechat()# 使用账号B对象发送信息wechat2.send_message(content="heihei")wechat2.send_image(imageid="hehe.jpg")

小结:
有两个类,在类中定义公共接口,在实例化时,一个类中的某一方法作用是实例化另一个类

1.1.3 抽象工厂模式(Abstract Factory)

'''
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)
  1. 相比工厂模式,又进了一步,不在工厂中具体实例化类,相当于对工厂进行了抽象。
  2. 类是对对象的抽象,抽象工厂是对类的抽象。

1.1.4 创建者模式–Builder

解决的问题:

我需要做一个功能,检测出图像中的某些特殊标记。我写了这样一个功能的类,构造它时,传入的是一张拍摄好的图像的fileName。 过了两天,我要把这个功能和其他功能联合起来,我需要的图像就变成了一个数组传入。于是我就加上了一个处理数组数据的构造函数。过了几天,数组又发生了变化,现在图像大小要求可变,没什么难度,新写一个构造函数,包含数组和尺寸。 又过了几天,图像需求又要变了,我之前的图像是三通道的,现在要求,单通道的图像也能处理,嗯,好吧,再加个构造函数。。。。写着写着,我发现上帝也看不懂我的代码了,于是,我就想减少构造函数的复杂度,我找到了Cpp的默认参数的特性,嗯,这样,几个构造函数可以“精巧”的利用默认参数,成功的缩减了构造函数的个数。。。正当我洋洋自得时,情况又变了,有些图像需要特殊的操作,比如强化、锐化或者旋转后,才能使用,为了不影响我类内部的功能实现,我选择在构造时,就可以判断是否需要做特殊操作,于是,我的所有构造函数上就都要加上一个额外的参数—特殊操作参数,ok,我吭哧吭哧的把所有的构造函数都改了,然后,就是函数声明的地方、定义的地方、调用的地方,还记得之前有过的默认参数嘛? 改用这些构造函数,那个酸爽,,,, 每次改之前稳定的代码中的调用的地方,我都要仔细的设计参数,小心翼翼的,改一个,编译一下,跑一下,测试一下结果。 这个时候,发现之前的所谓的“精巧”的设计,简直就是反人类,错一点点都不满足那种精巧了,然后就是铺天盖地的错误。 过了几天,我再回来想看我的代码,发现,脑子里面得把整个思路完全得走一边,才能看懂。没看懂内部逻辑,就别想正确大胆得调用。
事情发展到这个地步,我意识到,我应该去找设计模式了。

来源:https://zhuanlan.zhihu.com/p/58093669 评论

'''
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();

个人理解: 简单来说就是将需要创建的东西,打包放方法里面,方便统一管理调用

1.1.5 原型模式–Prototype

当创建对象成本较高时使用。如:一个对象需要再操作高代价的数据库之后才被创建,那么可以使用已经创建的对象,减少数据库的调用。

通俗理解:

当我们出版了一本书《大话设计模式 1.0版》,若10 年后我们觉得这本书跟不上时代了,这时候需要去重写一本《大话设计模式 2.0版》,那么我们是完全重写一本书呢?还是在原有《大话设计模式 1.0版》的基础上进行修改呢?当然是后者,这样会省去很多排版、添加原有知识等已经做过的工作。

来源:https://juejin.cn/post/7000534811697741832

'''
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)print(b.a, b.b, b.c)if __name__ == '__main__':main()

1.1.6 单例模式–Singleton

适用场景: 保证只有一个实例操作,用于资源调度、日志管理、信息注册等

'''
Singleton
'''**案例1** 类方式
# 实现__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)

案例2: 装饰器

def singleton(cls, *args, **kw):    instances = {}    def wrapper():    if cls not in instances:    instances[cls] = cls(*args, **kw)    return instances[cls]    return wrapper  
@singleton
class Animal(object):def __init__(self):passanimal1 = Animal()
animal2 = Animal()
print(id(animal1))
print(id(animal2))

参考

[1] https://refactoring.guru/design-patterns/factory-method
[2] https://zhuanlan.zhihu.com/p/322327467
[3] https://zhuanlan.zhihu.com/p/56202148
[4] https://blog.csdn.net/Burgess_zheng/article/details/86762248#t12
[5] https://zhuanlan.zhihu.com/p/105234299
[6] https://blog.csdn.net/qq_33511971/article/details/110168895
[7] https://www.cnblogs.com/littlefivebolg/p/9929016.html
[8] https://blog.csdn.net/qq_30758629/article/details/105842240
[9] https://blog.csdn.net/qq_40329976/article/details/103963327
[10] https://zhuanlan.zhihu.com/p/58093669
[11] https://blog.csdn.net/huxiaotong_exp/article/details/53981963
[12] https://zhuanlan.zhihu.com/p/591683145
[13] https://www.cnblogs.com/welan/p/9123803.html
[14] https://juejin.cn/post/7000534811697741832
[15] https://www.zhihu.com/tardis/zm/art/87524388?source_id=1005

http://www.lryc.cn/news/105528.html

相关文章:

  • 【JS】类 class
  • Ubuntu安装harbor(http模式)并随便上传一个
  • 《向量数据库指南》——腾讯云向量数据库Tencent Cloud Vector DB正式上线公测!提供10亿级向量检索能力
  • 1分钟解决github push/pull报错443
  • vue3学习-ref引用
  • Docker 容器转为镜像
  • 阿里云服务器免费试用及搭建WordPress网站
  • 整流二极管型号汇总,超齐全
  • MongoDB 操作命令
  • markdown高级写作技巧汇总
  • SpringBoot自动配置原理入门级理解
  • 2023 08.02 小记与展望
  • MaxPatrol SIEM 增加了一套检测供应链攻击的专业技术
  • 蓝桥杯上岸每日N题 第六期(求阶乘)!!!
  • Codeforces Round 889 (Div. 2)(视频讲解A——D)
  • K8s安全配置:CIS基准与kube-bench工具
  • linux安装python和部署Django项目
  • 00-Hadoop入门
  • SE-Net注意力机制详解
  • 商城免费搭建之java商城 开源java电子商务Spring Cloud+Spring Boot+mybatis+MQ+VR全景+b2b2c bbc
  • 推理加速 --- torch.compile
  • JS-----数据结构与算法(2)
  • 手把手安装TomCat;并部署JPress
  • tensorflow1.13分布式训练 参考资料 -教程原理
  • DP学习第五篇之礼物的最大价值
  • cURL error 1: Protocol “https“ not supported or disabled in libcurl
  • XCode升级后QT无法编译的问题
  • springboot编写mp4视频播放接口
  • 华为OD机试真题 JavaScript 实现【机器人活动区域】【2023Q1 200分】,附详细解题思路
  • C++中的静态分配和动态分配