《大话设计模式》阅读笔记 个人版
面向对象:易维护 易扩展 能复用
工厂模式:
什么是工厂:一个用于创造实例的类
应对有限个不会多变的算法需求
基本套路:
1 创建一个抽象基类
2 根据不同情况设计不同子类继承于抽象基类//继承
3 创建一个工厂类来依据不同情况生产不同算法子类的对象//多态
4 有新需求则需要新建子类并在工厂中修改代码实现生产此类对象的分支
5 在客户端低耦合地使用工厂
//计算器
* 工厂返回算法子类
策略模式:
定义:它定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户
策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,
只要在分析过程中听到需要在不用时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性
基本套路:
1 找到所有情况下各算法共同点---创建抽象基类
2 基于不同情况设计不同子类继承于抽象基类 一个算法相当于一种策略
3 创建上下文(Context)类 维护一个对策略对象的引用
4 对于新的需求则同样创建新的策略
5 客户端低耦合使用上下文类
//收银系统
* 上下文中实现抽象基类的目标方法 在里面调用具体算法的方法
单一职责原则:
准确解释:就一个类而言,应该仅有一个引起它变化的原因
软件设计真正要做的许多内容,就是发现职责并把那些职责相互分离
如果能够想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责
游戏设计中 界面的变化是和游戏本身没有关系的,界面是容易变化的,游戏逻辑是不太容易变化的,将它们分离开有利于界面的改动
基本套路:
分析问题,在构造类的时候想清楚使其改变的动机(一般不同场景就是不同职责 构建不同的类使职责单一化)
开放-封闭原则:
解释:软件实体(类、模块、函数等等)应该可以扩展,但是不可以修改
两大特征:对于扩展是开放的,对于更改是封闭的
此原则确保面对需求的改变却可以保持相对稳定,从而使得系统可以在第一个版本以后不断退出新的版本
对程序的改动是通过增加新代码进行的,而不是更改现有的代码
依赖倒转原则:
抽象不应该依赖细节,斜街应该依赖于抽象
要针对接口编程,不要对实现编程
里氏代换原则:子类型必定能够替换掉它们的父类型
只有当子类可以替换掉父类,软件单位的功能不受到影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为
高层模块不应该依赖底层模块,两者都应该依赖抽象
装饰模式:
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活
装饰模式是为已有功能动态添加更多功能的一种方式
基本套路:
1 创建组件类(父类)
2 创建装饰类继承于组件类,含有对组件类的一个实例,用于在其基础上进行装饰
3 创建众多具体的装饰类继承于装饰类,它们之间的实例可以互相装饰
4 依据装饰过程的不同得到不同的对象
代理模式:
对其他对象提供一种代理以控制对这个对象的访问
基本套路:
1 创建抽象类(基类)--公共接口
2 创建真实类继承于基类,含有具体的功能实现
3 创建代理类继承于基类,含有真实类的实例的引用
4 在代理中实现具体功能,可以在这里实现对真实类的封装,使其不可见
工厂方法模式:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到了其子类
区别于简单工厂模式:简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对客户端来说,去除了与具体产品的依赖
工厂方法模式把简单工厂的内部逻辑判断移到了客户端代码来进行,想要加功能本来是改工厂类,而现在是修改客户端
基本套路:
1 定义工厂方法所创建的对象的接口
2 定义抽象工厂,含有返回要被创建实例的方法
3 对于特定功能创建具体实用类继承对象接口
4 创建具体工厂类继承抽象工厂,针对不同实用类创建不同的工厂来生产相应的对象
5 客户端直接采用具体实用类的工厂来创建不同的对象
原型模式:
从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节
Clone对象:一般在初始化的信息不发生改变的情况下,克隆是最好的方法, 这既隐藏了对象创建的细节,又对性能是大大的提高
浅复制:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都扔指向原来的对象
深复制:把引用对象的变量指向复制过的新对象,二不是原有的被引用的对象
将原型实现可克隆接口,实现具体的克隆方法,客户端调用
模板方法模式:
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中
模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
优势:模板方法模式是通过把不变行为搬移到超类,去除子类中的重复代码
基本套路:
1 定义抽象顶级类--抽象模板,定义并实现了一个模板方法(具体的方法),它给出一个顶级逻辑的骨架,逻辑的组成步骤在相应的抽象操作中
abstract class AbstractClass{
public abstract void PrimitiveOperation1();
public abstract void PrimitiveOperation2();
public void TemplateMethod(){//具体的方法
PrimitiveOperation1();//逻辑
PrimitiveOperation2();
}
}
2 实现具体任务类继承于顶级类,实现父类定义的抽象方法
3 客户端采用多态来调用具体的方法
迪米特法则:
最少知识原则
如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用
在类的结构设计上,每一个类都应当尽量降低成员的访问权限:
白话解释:一个类包装好自己的private状态,不需要让别的类知道的字段或行为就不要公开
外观模式:
为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
个人理解:对复杂的系统进行封装,得到简单可用的接口,客户端仅需要了解外观接口即可
基本套路:
1 单独实现下面的子系统--各种功能类
2 实现外观类,来对下面子系统的功能进行整合封装
3 客户端无需了解下面的子系统,直接针对外观的接口进行调用,就可以充分的使用子系统
建造者模式:
又叫:生成器模式
建造者模式可以将一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象
指挥者:用它来控制建造过程,也用它来隔离用户与建造过程的关联
基本套路:
1 创建建造者,为创建一个产品对象的各个部件指定的抽象接口,含有共有的抽象方法(保证新添加的类中不会因为疏忽丢失功能)
2 创建具体产品的的建造者,继承于建造者,实现具体的抽象方法
3 创建一个指挥者,构建一个使用建造者接口的对象,内部含有建造者的一个引用,创建指挥者实例时传入指定创建者(基于多态)
4 客户端通过指挥者来创建不同的产品
什么时候用:
主要用于创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化
观察者模式:
又叫:发布-订阅模式
定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己
基本套路:
1 定义抽象通知者--抽象类/接口 把所有对观察者对象的引用保存在一个聚集里 提供接口来增加或删除观察者对象
2 定义抽象化观察者,在得到主题的通知时更新自己--更新接口 Update方法
3 定义具体主题或者通知者,将有关状态存入具体观察者对象,主题内部状态发生改变时,给所有登记过的观察者发出通知--继承于抽象通知者
4 定义具体观察者,实现更新接口来使自身的状态与主题的状态相协调,保存一个指向具体通知者对象的引用
作用:解除耦合,让耦合的双方都依赖与抽象,而不是依赖于具体
委托(delegate):
是一种引用方法的类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为
委托方法的使用可以像其他任何方法一样,具有参数和返回值
委托可以看作是对函数的抽象,是函数的‘类’,委托的实例将代表一个具体的函数
一个委托可以搭载多个方法,所有方法被依次唤起
可以使得委托对象所搭载的方法并不需要属于同一个类
C#:
delegate void EventHandler();//声明了一个特殊的类 函数的类
用:
public event EventHandler Update;//声明了一个事件委托变量叫 Update
huhansan.Update += new EventHandler(tongshi1.CloseStockMarket);//将‘tongshi1.CloseStockMarket’这个方法委托给‘huhansan.Update’这个方法
要求:委托对象所搭载的所有方法必须具有相同的圆形:相同的参数列表,相同的返回值类型
抽象工厂模式:
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
基本套路:
1 定义抽象工厂接口,包含所有的产品创建的抽象方法
2 定义具体工厂类,继承于抽象工厂接口,实现具体生产不同类的对象的方法
3 定义抽象产品接口,含有此类产品的相关任务
4 定义具体的产品类,继承于抽象产品接口,对抽象产品的具体实现
5 为创建不同的产品对象,客户端应使用不同的具体工厂
ps:反射代替switch 添加配置文件避开修改代码
状态模式:
当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类
适用于:
当控制一个对象状态转换的条件表达式过于复杂时,把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化
基本套路:
1 定义一个抽象状态类--一个接口/抽象类,来封装与上下文的一个特定状态相关的行为
2 定义具体状态类,每个子类实现一个与上下文的状态相关的行为
3 定义上下文类,来维护一个具体状态子类的实例,这个实例定义当前状态
目的:消除庞大的条件分支语句
适配器模式:
将一个类的接口转换成客户希望的另外一个接口
适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
解决问题:需要的东西就在眼前,但却不能使用,而短时间又无法改造它,这是就要想办法适配它
基本套路:
1 特殊的类
2 定义目标类,客户所期待的接口--具体的或抽象的类或接口
3 定义适配器继承于目标类,并在其中含有特殊类对象的实例的引用,通过方法对其进行封装(类似于代理)
备忘录模式:
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态
基本套路:
1 定义属性会变的类,并在其中定义保存状态及恢复状态的方法
2 定义存储箱类,来针对具体属性进行存储
3 定义管理者,含有对存储箱对象的应引用,并定义get/set方法获取或设置存储箱的状态
4 客户端使用管理者和来恢复存储的状态
组合模式:
将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性
基本套路:
1 定义基本模型--抽象类,在其中定义都会用到的方法(抽象)
2 定义具体的事物类,继承于基本类,来实现具体的方法(枝节点/叶子节点)
3 客户端相同对待基本对象和组合对象
透明方式:
抽象类中定义所有的规范方法
在具体实现类中如没有此功能,则为空,什么也不做或给出提示
好处:所有具体类具备完全一致的行为接口
安全方式:
抽象接口中对于不同具体类之间的差异部分不做同一规定,在具体类中自己来定义所需方法
好处:安全 但是由于不具备完全一致的接口,客户端的调用需要做相应的判断
什么时候用:
需求中是体现部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,同一地使用组合结构中所有对象时
迭代器模式:
提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示
实现Iterable接口
单例模式:
保证一个类仅有一个实例,并提供一个访问它的全局访问点
让类自身负责保存它的唯一实例
将类的构造器设置为private,外部就不可以采用new来创造它的实例
是否创造此类的实例由它自己说了算
基本套路:
1 将类的构造器设置为private,内部定义静态成员指向本类的实例的引用
2 类内添加public的实例化方法,来进行自己管理
双重锁定:
if(instance == null){/////
lock(syncRoot){
if(instance == null){////
instance = new Singleton();
}
}
}
静态初始化:在类加载时将自己实例化 --饿汉式单例类
在第一次被引用时,才会将自己实例化 --懒汉式单例类
区别:饿汉式在类一加载就实例化,要提前占用系统资源 线程安全
懒汉式面临线程安全问题,需要做双重锁定这样的处理来保证安全
桥接模式:
将抽象部分与它的实现部分分离,使它们都可以独立得变化
通俗理解:实现系统可能有多角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来让它们独立变化,减少它们之间的耦合
合成/聚合复用原则:尽量使用合成/集聚合,尽量不要使用类继承
合成关系:翅膀--->大雁 聚合关系:大雁--->雁群
各类软件--->软件 软件--->手机品牌
命令模式:
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作
基本套路:
1 定义命令类,含有接收命令对象的引用,以及抽象的执行方法
2 定义具体命令类,实现执行方法,方式为调用接收者相应的操作
3 定义调用者类,要求该命令执行这个请求
4 定义接收者类,执行与请求相关的操作
职责链模式:
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止
基本套路:
1 定义处理请求的接口--抽象类,含有设置继任者的方法,以及处理请求的抽象方法
2 定义具体处理者类继承于抽象类,实现具体职责--自己能处理则处理,不能交给后继者
中介者模式:
又叫调停者模式
用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互
基本套路:
1 定义中介者类--抽象类,定义用于协调具体实例间问题的抽象方法
2 定义具体中介者类,继承于抽象类,含有所有需要维护关系的类的实例,并实现协调方法
3 定义由各类泛化来的抽象类,含有中介者类的实例引用,并在构造器中传入中介者
4 定义具体的各类,完成自己的功能方法
享元模式:
运用共享技术有效地支持大量细粒度的对象
目的:共享对象,节约资源
基本套路:
1 发现需要大量创建的各种实例间的相同与不同之处
2 相同的部分为内部状态,写入一个类中
3 不同的部分为外部状态,在外部定义新的类,并在2中的类中使用指向其实例的引用
4 通过hashmap存储,设置key,如果key相同其已经实例过此类的实例则直接返回,并在客户端修改外部状态
解释器模式:
给定一个语言,定义它的文法的一种表示,并定义一个解析器,这个解析器使用该表示来解释语言中的句子
基本套路:
1 定义抽象解释类,这个接口为抽象语法树中所有的节点所共享
2 定义具体文法解释类,继承于抽象类,实现不同文法解释的方法
3 客户端采用case分支创建不同文法解释实例
访问者模式:
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作
基本套路:
1 定义抽象访问者,根据固定的数据结构定义抽象visit操作(男人/女人)
2 定义具体的访问者类,继承于抽象访问者,实现由每个Visitor声明的操作(不同状态:成功/失败 结婚/恋爱 ...)
3 定义一个抽象元素类,定义抽象Accept操作,以一个访问者为参数
4 定义具体的元素类,继承与抽象元素类,实现Accept方法(利用双分派技术,实现处理与技术结构的分离)
5 定义对象结构类,实现对所有元素的管理,提供一个高层的接口以允许访问者访问它的元素
使用情况少
本节完...