延迟到子类: 定义一个虚函数,让子类来重写获实现他。这其实就是支持子类去 变化。
扩展: 继承 + 多态,即,子类继承基类 并对其虚函数进行 override
依赖: 一般指编译时依赖,如:A依赖B,那么在编译的时候,编译器需要先编译 B,才能再编译 A。本篇指的一般是编译时依赖,如果是运行时依赖会特别说明。
在软件的 变化 和 稳定 中间寻找隔离点,从而分离他们,从而更好地管理变化。
在应用设计模式时,关键就是要区分出软件体系结构中 哪些是稳定的,哪些是变化的。
要 动态地看 一个软件的结构层次。
拿到一张设计模式的类图,重点要区分出类图中哪些是稳定的,哪些是变化的。
早绑定:一个晚的东西调用一个早(库)的东西。
晚绑定:反过来。(由库来调用我们写的东西。)这是该模式在代码中的体现形式。
表现形式: 多态。定义一个基类,我们可以扩展其子类并重写其虚函数,从而实现变化。而调用这些方法的接口不用变。
代码中如果出现了if else
或switch case
的这种结构,通常是使用策略模式的特征,此时你就要考虑一下未来会不会增加其他的else if
分支,如果有可能那么此时应该使用策略模式。但如果if else
里判断的是星期几,情况固定,那么就不必使用策略模式。
“当你看到if else
时,你就闻到了代码中的坏味道”——马丁·弗勒
摘自:https://www.midlane.top/wiki/pages/viewpage.action?pageId=26181878
表现形式: 组合 + 多态。
摘自:https://www.midlane.top/wiki/pages/viewpage.action?pageId=26181888
装饰模式达到的效果:各个类在编译时是各司其职,但可以通过编写代码实现在运行时随意装配组合功能(但编译时,没有实现这种功能的类)。
桥模式和装饰模式很相似,它们的区别是继承体系的数量不同。装饰模式只有一个继承体系;而桥模式有两个继承体系,他们之间由一个指针联系起来,这个指针就像桥一样。
当一个类中有多个非常强的变化维度时,就把属于某个变化维度的成员打包在一起单独作为一个基类,并且引一个指针指向它。
解决的问题: 由于需求的变化,需要创建的对象的具体类型经常变化。我们需要避免直接new
一个对象,从而避免这种紧耦合。
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式使得一个类的实例化延迟(目的:解耦,手段:虚函数)到子类。
和工厂方法模式很像都是用来避免在创建对象时的紧耦合。但抽象工厂解决的是创建【一系列相互依赖的对象】的创建工作。
可以将工厂方法 看作 抽象工厂的一个特例,即,要创建的对象只有一个,而不是一个系列。
使用场景和工厂模式很相似,都是用来避免在创建对象时的紧耦合。
什么时候使用该原型:当使用工厂方法创建对象所需要的步骤很复杂,且 需要考虑 并 保留对象的中间状态时,就需要使用原型模式。
该模式和模板方法模式很像,但构建器模式的思考方式更加细化,他是从构建对象的角度来看的。
构建器模式将复杂对象的构建与其表示相分离,使得同样的构建流程(稳定)可以创建不同的表示(变化)。
单例模式解决的不是抽象问题,而是性能问题。
单例模式保证某个类只有一个实例,并提供一个该实例的全局访问点。
单例模式的实现一般有两种方式:
懒汉模式: 第一次用到类的实例时才实例化。
饿汉模式: 单例类定义的时候就进行实例化。
更多懒汉模式和饿汉模式可以参考这里。
普通的单例模式实现方法是非线程安全的,因此多线程编程中使用单例模式涉及到锁,这里牵扯到很多问题。所以先记几篇博客:
Boost线程库学习笔记
boost::scope_lock简要总结
单例模式和线程安全
单例模式和线程安全
单例模式解决的也不是抽象问题,而是性能问题。即,当需要创建很多对象时,我们让他们共享一个对象,而不是真的去创建这么多对象。
运用共享技术有效地支持大量细粒度的对象。
使用享元模式创建的对象一般都是只读的,否则共享就不成立了。
将系统内的变化圈起来,对系统外提供统一的接口访问系统内。
对外松耦合,对内高内聚。
为其他对象提供一种代理以控制(隔离,使用接口)对这个对象的访问。
增加间接层,在间接层中实现一些不为外界所知的功能。在具体实现中,间接层中需要做的工作可能非常庞大。
将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的类可以一起工作。
(李建忠C++设计模式第17集17分10秒处讲解了四种接口隔离模式的区别)
备忘录模式的思想是:在不破坏封装性的前提下,捕获一个对象的内部状态(即,不能让外部知道对象的实现细节),并在该对象之外保存这个状态,这样以后就可以将该对象恢复到原先保存的状态。
如今该模式的实现方式已经基本脱离了面向对象编程,而是采用序列化等方式。所以,对于该模式我们只需知道其思想即可,而实现方式另外去学习。
组合模式将对象组合成 树形结构 以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组件对象的使用具有一致性(稳定)。
组合模式采用树形结构来实现普通存在的对象容器,从而将“一对多”的关系转化为“一对一”的关系,使得客户代码可以一致地(复用)处理对象和对象容器,无需关心处理的是单个对象,还是组合的对象容器。
在C++中该设计模式已经被STL标准库中的迭代器iterator
所取代(用模板+适配器模式实现),而在其他语言中遍历不同类型的容器确实是用迭代器模式实现的。
可以做到在运行时辨析哪个处理者可以处理这个请求。
不过该模式在今天也基本用的很少了。
把行为抽象为对象(类似于函数对象)。
目前,在C++中,函数对象已经基本取代了命令模式,但命令模式在Java等其它语言得到了广泛的应用。
表示一个作用于某对象结构中的各元素的操作。使得可以在不改变(稳定)各元素的类的前提下定义(扩展)作用于这些元素的新操作(变化)。
弄清楚上图中哪些部分可变,哪些部分不可变很重要。
访问器模式虽然能够动态地为整个对象体系中的所有类添加新方法,但是,使用该模式的前提条件也是很苛刻的。所以,在实际开发中很少有能用该模式的情景。
应用场景:解析类似于 “肆仟叁佰伍拾陆”,这样的文法,将其转换成数字表示,就可以使用解析器模式。
解析器模式比较是和简单的文法表示,对于复杂的文法表示,解析器模式会产生很大的类层次结构。目前,解析器模式用的也比较少。