TODO 需要补充 行为型模式 结构型模式 小结等
七大设计原则
- 1、单一职责原则【SINGLE RESPONSIBILITY PRINCIPLE】:一个类负责一项职责.
- 2、里氏替换原则【LISKOV SUBSTITUTION PRINCIPLE】:继承与派生的规则.(子类可替换父类)
- 3、依赖倒转原则【DEPENDENCE INVERSION PRINCIPLE】:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。即针对接口编程,不要针对实现编程。
- 4、接口隔离原则【INTERFACE SEGREGATION PRINCIPLE】:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。
- 5、迪米特法则【LOW OF DEMETER】:高内聚 低耦合 – high cohesion low coupling(类只做一类事情,类的成员函数关联尽量少)
- 6、开闭原则【OPEN CLOSE PRINCIPLE】:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
- 7、组合/聚合复用原则【Composition/Aggregation Reuse Principle(CARP) 】:尽量使用组合和聚合少使用继承的关系来达到复用的原则。
24 种设计模式
创建型模式基于对象的创建机制,隔离了对象的创建细节,使代码能够与要创建的对象的类型相互独立
结构型模式用于设计对象和类的结构,使它们可以相互协作以获得更大的结构
行为型模式主要关注对象的责任,用来处理对象之间的交互,以实现更大的功能
创建型模式
- 1、抽象工厂模式(Abstract factory pattern): 提供一个接口, 用于创建相关或依赖对象的家族, 而不需要指定具体类.
- 2、生成器模式(Builder pattern): 使用生成器模式封装一个产品的构造过程, 并允许按步骤构造. 将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示.
- 3、工厂模式(factory method pattern): 定义了一个创建对象的接口, 但由子类决定要实例化的类是哪一个. 工厂方法让类把实例化推迟到子类.
- 4、原型模式(prototype pattern): 当创建给定类的实例过程很昂贵或很复杂时, 就使用原形模式.
- 5、单例模式(Singleton pattern): 确保一个类只有一个实例, 并提供全局访问点.
- 6、多例模式(Multition pattern): 在一个解决方案中结合两个或多个模式, 以解决一般或重复发生的问题.
结构型模式
- 1、适配器模式(Adapter pattern): 将一个类的接口, 转换成客户期望的另一个接口. 适配器让原本接口不兼容的类可以合作无间. 对象适配器使用组合, 类适配器使用多重继承.
- 2、桥接模式(Bridge pattern): 使用桥接模式通过将实现和抽象放在两个不同的类层次中而使它们可以独立改变.
- 3、组合模式(composite pattern): 允许你将对象组合成树形结构来表现”整体/部分”层次结构. 组合能让客户以一致的方式处理个别对象以及对象组合.
- 4、装饰者模式(decorator pattern): 动态地将责任附加到对象上, 若要扩展功能, 装饰者提供了比继承更有弹性的替代方案.
- 5、外观模式(facade pattern): 提供了一个统一的接口, 用来访问子系统中的一群接口. 外观定义了一个高层接口, 让子系统更容易使用.
- 6、亨元模式(Flyweight Pattern): 如想让某个类的一个实例能用来提供许多”虚拟实例”, 就使用蝇量模式.
- 7、代理模式(Proxy pattern): 为另一个对象提供一个替身或占位符以控制对这个对象的访问.
行为型模式
- 1、责任链模式(Chain of responsibility pattern): 通过责任链模式, 你可以为某个请求创建一个对象链. 每个对象依序检查此请求并对其进行处理或者将它传给链中的下一个对象.
- 2、命令模式(Command pattern): 将”请求”封闭成对象, 以便使用不同的请求,队列或者日志来参数化其他对象. 命令模式也支持可撤销的操作.
- 3、解释器模式(Interpreter pattern): 使用解释器模式为语言创建解释器.
- 4、迭代器模式(iterator pattern): 提供一种方法顺序访问一个聚合对象中的各个元素, 而又不暴露其内部的表示.
- 5、中介者模式(Mediator pattern) : 使用中介者模式来集中相关对象之间复杂的沟通和控制方式.
- 6、备忘录模式(Memento pattern): 当你需要让对象返回之前的状态时(例如, 你的用户请求”撤销”), 你使用备忘录模式.
- 7、观察者模式(observer pattern): 在对象之间定义一对多的依赖, 这样一来, 当一个对象改变状态, 依赖它的对象都会收到通知, 并自动更新.
- 8、状态模式(State pattern): 允许对象在内部状态改变时改变它的行为, 对象看起来好象改了它的类.
- 9、策略模式(strategy pattern): 定义了算法族, 分别封闭起来, 让它们之间可以互相替换, 此模式让算法的变化独立于使用算法的客户.
- 10、模板方法模式(Template pattern): 在一个方法中定义一个算法的骨架, 而将一些步骤延迟到子类中. 模板方法使得子类可以在不改变算法结构的情况下, 重新定义算法中的某些步骤.
- 11、访问者模式(visitor pattern): 当你想要为一个对象的组合增加新的能力, 且封装并不重要时, 就使用访问者模式.
设计模式参考链接:
设计模式-创建型
创建型-01 工厂模式
工厂模式:主要用于抽象对象的创建过程,让用户可以指定自己想要的对象而不必关心对象的实例化过程
创建型-02 抽象工厂模式
抽象工厂模式:提供一个接口, 用于创建相关或依赖对象的家族, 而不需要指定具体类
用 Python 实现设计模式——工厂模式
创建型-03 生成器模式
生成器模式:使用生成器模式封装一个产品的构造过程, 并允许按步骤构造. 将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示.
- 概念
- 特点
- 建造者模式注重一步一步创建对象
- 元对象不允许被消费者对象直接调用。 元对象 -> 中间对象(不同产品种类) -> 消费者
- 应用场景
- 对象的创建步骤可以独立于创建过程的时候
- 被创建的对象拥有不同的表现形式
- 特点
Python 设计模式生成器模式,建造,者
建造者模式 —— Python 描述
创建型-04 原型模式
原型模式:支持复制类中的对象,且更新其部分属性. 用于简化外部操作,提供简单接口等等
- 特点
- 通过对传入对象进行深拷贝。可以通过 copy.deepcopy 另一种方式来实现。只是类中集成了此功能,从而更方便使用。
- 应用场景
- 原型模式用于创建对象的浅副本
- 数据间共享
- 原型模式用于创建对象的完全副本
- 需要复制类中的对象。
- 需要复制类中的对象,并对返回的对象更新其部分参数。
- 原型模式用于创建对象的浅副本
1 | import copy |
创建型-05 单例模式
单例模式:一个类只能被实例化一次,实例对象在第一次实例化时就已经固定,后续的实例化用的都是第一次实例化的对象
- 概念
- 应用场景
- 整个系统中类只能出现一个实例时,比如 配置文件类 AppConfig 等等
- 应用场景
单例模式是一个经典设计模式,简要的说,一个类只能被实例化一次,实例对象在第一次实例化时就已经固定,从第二次以后其实一直都是用的第一次实例化的对象,相当于全局。
创建单例模式的方法:
- 使用模块
- 使用
__new__
- 使用 metaclass
- 使用 装饰器
- 静态方法
- 类方法
- 名称覆盖
- 属性共享
创建单例模式方法-使用模块:
Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类
1 | # mysingleton.py |
创建单例模式方法-使用__new__
:
1 | class Demo: |
创建单例模式方法-元类 metaclass:
1 | class SigletonMetaClass(type): |
创建单例模式方法-装饰器:
1 | # 函数装饰器 |
创建单例模式方法-静态方法:
1 | class Singleton(object): |
创建单例模式方法-类方法:
1 | class Singleton(object): |
创建单例模式方法-名称覆盖:
用实例名覆盖类名后,执行 Singleton() 就是在调用 call() 函数,总是返回自身。
1 | class Singleton(object): |
创建单例模式方法-属性共享:
1 | class Singleton(object): |
实例对象的私有属性存放在 dict 中。因此,将所有对象指向同一个属性 Singleton._state,即便它们的 id 值 不同,由于共享属性仍实现了单例效果。
TODO 复杂情况下的单例模式
多线程下的单例模式应用:
1 | def singleton(cls): |
上述代码中定义了 singleton 类装饰器,装饰器在预编译时就会执行,利用这个特性,singleton 类装饰器中替换了类原本的new与init方法,使用 singleton_new 方法进行类的实例化,在 singleton_new 方法中,先判断类的属性中是否存在it属性,以此来判断是否要创建新的实例,如果要创建,则调用类原本的new方法完成实例化并调用原本的init方法将参数传递给当前类,从而完成单例模式的目的。
1 | # 加上线程锁 |
参考链接:
创建型-06 多例模式
多例模式:多例模式允许存在有限个实例(多例模式又分为有上限模式和无上限模式,无上限模式和直接 new 一个对象差不多,此处不做讨论)
- 特点
- 允许有多个实例;
- 多例类自己负责创建、管理自己的实例,并向外界提供自己的实例(这点根单例模式相同)
单例模式仅创建一个对象。多例模式可以创建 有限个对象
详情请参考 单例模式
设计模式-结构型
结构型-01 适配器模式
适配器可以理解为万能接口,各种类可以通过这个接口然后被调用,达到万能转换的效果。
他的实现是以我们定义的适配器函数来分类,将各种类的不同方法注册到对应的分类函数中,调用的时候只需要使用分类名,这样就达到了适配所有类不同方法的效果.
1 | class A: |
结构型-02 桥接模式
桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
参考链接:
结构型-03 组合模式
- 优点
- 节点增加和减少是非常自由和方便的,这也是树形结构的一大特点;
- 所有节点,不管是分支节点还是叶子结点,不管是调用一个结点,还是调用一个结点群,都是非常方便的
- 缺点
- 由于叶子结点和分支结点直接使用了实现类,而不方便使用抽象类,这大大限制了接口的影响范围;若结点接口发生变更,对系统造成的风险会比较大。
- 使用场景
- 维护部分与整体的逻辑关系,或者动态调用整体或部分的功能接口,可以考虑使用组合模式。例如,非常多的操作系统(如 Linux)都把文件系统设计成树形结构,再比如说分布式应用中借助 Zookeeper,也可以组织和调用分布式集群中的结点功能。
参考链接:
结构型-04 装饰者模式
TODO 装饰器的缺点
装饰者模式:使用装饰器来动态的添加功能。例如日志记录、权限认证等等
- 优点
- 能够在不修改任何底层代码情况下,给已有对象赋予新的职责。
- 代码量减少,可复用,易维护,增加可读性
- 缺点
当装饰器已经作用于某函数,而你想撤销它,那么可以访问 wrapped 属性来访问原始函数。 不建议使用,多装饰器时,不可控。
参考链接:
结构型-05 外观模式
外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
- 概念简述
- 将复杂的方法简化为一个类的函数接口,便于统一调用。类似于函数封装。
- 优点
- 优点在于对客户屏蔽子系统组件,减少了客户处理的对象数目并使得子系统使用起来更加容易,它实现了子系统与客户之间的松耦合关系,并降低了大型软件系统中的编译依赖性,简化了系统在不同平台之间的移植过程;
- 缺点
- 缺点在于不能很好地限制客户使用子系统类,而且在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。
1 | # 简单的样例 |
参考链接:
结构型-06 亨元模式
亨元模式:用于解决资源和性能压力时会使用到的设计模式,它的核心思想是通过引入数据共享来提升性能。
- 概念
- 重点在于将不可变(可共享)的属性与可变的属性区分开
- 在多个对象有相同属性,但又有各自不同属性时,享元模式可以对相同属性那部分进行数据共享,从而提升性能。
1 | from enum import Enum |
该示例中,在new方法中实现类不可变数据的共享。在init方法中实现了可变数据的独立,即不共享。
参考链接:
结构型-07 代理模式
为其他对象提供一种代理以控制对这个对象的访问.通俗的来讲代理模式就是我们生活中常见的中介
- 使用场景
- 一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用
- 远程代理,也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。
- 虚拟代理,是根据需要创建开销大的对象。通过它来存放实例化需要很长时间的真是对象。用于惰性求值,将一个大计算量对象的创建延迟到真正需要的时候进行。例如 html 中,图片需要 load 很久,所以通过虚拟代理来代替真实的图片
- 安全代理,或叫保护/防护代理:控制对敏感对象的访问。用来控制真实对象访问时的权限
- 智能(引用)代理:在对象被访问时执行额外的动作。此类代理的例子包括引用计数和线程安全检查。是指当调用真实的对象时,代理处理另外一些事
参考链接:
设计模式-行为型
行为型-01 责任链模式
责任链模式(Chain of responsibility pattern): 通过责任链模式, 你可以为某个请求创建一个对象链. 每个对象依序检查此请求并对其进行处理或者将它传给链中的下一个对象.
参考链接:
行为型-02 命令模式
命令模式(Command pattern): 将”请求”封闭成对象, 以便使用不同的请求,队列或者日志来参数化其他对象. 命令模式也支持可撤销的操作.
1 | # -*- coding: utf8 -*- |
参考链接
行为型-03 解释器模式
解释器模式(Interpreter pattern): 使用解释器模式为语言创建解释器.
优点:
- 可扩展性比较好,灵活。
- 增加了新的解释表达式的方式。
- 易于实现简单文法。
缺点:
- 1、可利用场景比较少。
- 2、对于复杂的文法比较难维护。
- 3、解释器模式会引起类膨胀。
- 4、解释器模式采用递归调用方法。
使用场景:
- 1、可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
- 2、一些重复出现的问题可以用一种简单的语言来进行表达。
- 3、一个简单语法需要解释的场景。
行为型-04 迭代器模式
迭代器模式(iterator pattern): 提供一种方法顺序访问一个聚合对象中的各个元素, 而又不暴露其内部的表示.
行为型-05 中介者模式
中介者模式(Mediator pattern) : 使用中介者模式来集中相关对象之间复杂的沟通和控制方式.
行为型-06 备忘录模式
备忘录模式(Memento pattern): 当你需要让对象返回之前的状态时(例如, 你的用户请求”撤销”), 你使用备忘录模式。
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态
行为型-07 观察者模式
观察者模式(observer pattern): 在对象之间定义一对多的依赖, 这样一来, 当一个对象改变状态, 依赖它的对象都会收到通知, 并自动更新.
行为型-08 状态模式
状态模式(State Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类.
应用场景:当控制一个对象的状态转换的条件表达式过于复杂时,把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化
行为型-09 策略模式
策略模式(strategy pattern): 定义了算法族, 分别封闭起来, 让它们之间可以互相替换, 此模式让算法的变化独立于使用算法的客户.
行为型-10 模板方法模式
模板方法模式(Template pattern): 在一个方法中定义一个算法的骨架, 而将一些步骤延迟到子类中. 模板方法使得子类可以在不改变算法结构的情况下, 重新定义算法中的某些步骤.
行为型-11 访问者模式
访问者模式(visitor pattern): 当你想要为一个对象的组合增加新的能力, 且封装并不重要时, 就使用访问者模式.