Head First设计模式第一课:策略模式
刚刚看《Head First 设计模式》,第一章讲了一个故事: 设计师Joe设计了只鸭子,但董事会(难道不是执行经理管这事)要求每六个月改变产品; 于是乎什么飞鸭、烤鸭、机器鸭、橡胶鸭……乱七八招的都来了,而且你还不知道下次是什么变态要求! 怎么办? 关于编程的方法:继承多态都无用,因为下次的代码改动量太大,并且需要改动多处原有代码。 那么怎的办!? 呵呵,在这危机时刻(Joe面临炒鱿鱼的危险),设计模式推出了两条原则:
1. 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
2. 针对接口编程,而不是针对实现编程。
最后奇迹出现,Joe大放异彩!
Head First设计模式第二课:观察者模式
学习了设计模式第二课:观察者模式(Observer),这是一个一对多的问题,所谓”牵一发而动全身“,主题的状态决定观察者的动作。
观察者模式 ── 在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。
新建主题对象 A
新建观察者 B(传入主题对象 A)
拷贝主题对象 A
注册观察者(把自个传入主题对象 A)
主题对象 A 中加入观察者 B, 依赖完成
主题状态改变 驱动 观察者动作 [push方式]
观察者动作 [pull方式]
对应接口:
主题接口 (主题对象)
观察者接口 (观察者)
外部动作接口 (观察者)
观察者利用主题接口向主题注册,而主题利用观察者接口通知观察者。 ── 松耦合
OO原则:
封装变化
多用组合,少用继承
针对接口编程,不针对实现编程
为交互对象之间的松耦合设计而努力
Head First 设计模式: 第三课 装饰者模式
装饰者模式(Decorator),以 Starbuzz Coffe 的多风味咖啡为例。
a. 饮料抽象类 A ;
b. 调料抽象类 B 继承到 A ;
c. 饮料类 C 继承 A ;
d. 调料类 D 继承 B,并引入 A 对象;
e. 用调料 D 装饰 B,嵌套直到需求完全;
f. D 可以在 C 的行为前/后加上自己的代码(行为),也可完全代替 C 的行为;
以星巴兹咖啡为例的装饰者模式定义: 动态地将责任附加到对象上。诺要扩展功能,装饰者提供了比继承更有弹性的替代方案。
OO原则:OO原则(开放 - 关闭): 对扩展开放,对修改关闭。
Head First 设计模式: 第四课 工厂模式
简单工厂模式 (Simple Facory Pattern): 中间类(也可能是静态类) 调用实现类,面对新的实现类需要修改中间类代码 [ 开放扩展,关闭修改 ]
工厂方法模式(Factory Method Pattern): 定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
[ 把创建者和产品类分开,解耦的方法,就是把行为选择权交由子类实现(超类抽象createPizza方法) ]
不能让高层组建依赖低层组件,趋于依赖”抽象”。
抽象工厂模式 : 提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
OO原则 - > 依赖倒置原则 ( Dependemcy Inversion Principle ) : 要依赖抽象,不要依赖具体类
· 变量不可以持有具体类的引用;
· 不要让类派生自具体类;
· 不要覆盖基类中已实现的方法。
Head First 设计模式: 第五课 单件模式
单件模式: 确保一个类只有一个实例,并提供一个全局访问点。
让类自己负责保存它的唯一实例。通过截取创建新对象的请求,保证没有其他的实例被创建。与此同时提供访问对象的方法。 (这里并不是说只能 new 一个类实例,而是保持一个类实例 )
a. 一个私有的静态属性;
b. 私有的构造函数; (也有推荐析构函数也使用私有标示,但这样怎样销毁对象? 再来个 public 方法?)
c. 一个公有的静态方法获取类的唯一实例; (在这个方法中判断和 new 对象,即使第一次实例对象也是调用它,除非你能攻破第2点)
d. 防止用户克隆(__clone())类实例)
Head First 设计模式: 第六课 命令模式
命令模式: 将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。(当需要将发出请求的对象和执行请求的对象解耦的时候,使用命令模式。)
在这章最后的总结我第一次留意这句话: 你的工具箱变重了!对于命令模式没有很好的理解,烦恼这个模式的意义所在: 把”命令”封装在一个类中(接口),然后调用者对这个类(接口)进行操作。 似乎普通的模式都是这么干的,不过它强调 “松耦” 的概念。按照这个的行为也确实容易维护。合理使用接口和继承不是那么简单,但不会这么的死板。
当不想返回一个有意义的对象时,空对象很有用。
Head First 设计模式: 第七课 适配器模式
适配器模式: 将一个类的接口,转换成客户期望的另一个接口。适配器让原来接口不兼容的类可以合作无间。
适配器模式过程(客户无须知道被适配者接口是什么,而被适配者接口无须修改):
1. 客户通过目标接口调用适配器的方法对适配器发出请求;
2. 适配器使用被适配者接口把请求转换成被失陪者的一个或多个调用接口;
3. 客户接受收到调用的结果,但并未察觉这一切是适配器在起转换作用。
外观模式: 提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
设计原则
最少知识原则:只和你的密友谈话。
· 装饰者 ── 不改变接口,但加入责任。
· 适配器 ── 将一个接口转换成另一个接口。
· 外观 ── 让接口更简单。
Head First 设计模式: 第八课 模板方法模式
模板方法模式: 在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。(使用方法把算法定义成一组步骤,让后让子类实现步骤)
hook(钩子): 在超类中默认不做任何事,子类可以视情况决定是不是覆盖他们。
[当子类 '必须' 提供算法中某个方法和步骤的实现时,使用抽象方法。 如果算法的这个部分是可选的,就使用钩子。]
OO 设计原则
好莱坞原则: 别调用(打电话给)我们{高层组件},我们会调用(打电话给)你{低层组件}。(将决策权交给高层模块)
· 模板模式 ── 子类决定如何实现算法中的某些步骤;
· 策略 ── 封装可互换的行为,然后使用委托来决定要采用哪一个行为;
· 工厂方法 ── 由子类决定实例化那个具体类;
Head First 设计模式: 第九课 迭代器模式
迭代器模式: 提供一种方法顺序访问一个聚合对象中的各个元素(不必在意其数据结构),而不是暴露其内部的表示。
(适配器??相似,一个聚合对象,一个连接多个类)
组合模式: 允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。
(叶子节点、组合节点!有点头晕,回想起当年C++时的无穷指针恐惧症)
设计原则: 一个类应该只有一个引起变化的原因。── 内聚
模式对比:
· 策略 ── 封装可互换的行为,并使用委托决定使用哪一个;
· 适配器 ── 改变一个或多个类的接口;
· 迭代器 ── 提供一个方法来遍历集合,而无须暴露集合的实现;
· 外观 ── 简化一群类的接口;
· 组合 ── 客户可以将对象的集合以及个别的对象一视同仁;
· 观察者 ── 当某个状态改变时,允许一群对象能被通知到;
Head First 设计模式: 第十课 状态模式
状态模式: 允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
——> 策略模式: 由客户主动指定context对象所要组合的策略对象是哪一个。
· 把各个状态分别继承于状态接口, 并得到上下文类对象;
· 在上下文类中,所有的状态都在构造器(主类)中创建并赋值, 配合函数处理状态(调用状态对象);
· 当前状态在状态对象集合中游走改变,以反应出context内部的状态,因此,context的行为也会跟着改变。(由上下文类和当前状态决定之后状态)
模式对比:
· 状态 ── 封装基于状态的行为,并将行为委托到当前状态;
· 策略 ── 将可以互换的行为封装起来,然后使用委托的方法,决定使用哪一个行为;
· 模板方法 ── 由子类决定如何实现算法种的某些步骤;
Head First 设计模式: 第十一课 代理模式
OOP村齐家的少爷喜欢上了尹家的小姐,但有鉴于礼法,双方长辈反对, 两个年轻人不能长时间见面。于是齐少爷的书童 和 尹小姐的丫环当起了连络人。 尹小姐想多了解齐少爷,派丫环去探探舌漏,丫环找到从小就跟着齐家少爷的书童,书童乘机说尽好话…… [ 这里丫环就是小姐的代理; 小姐要了解少爷,所以小姐是客户对象,丫环是客户辅助对象,书童是服务辅助对象,少爷是服务对象; 这个模式叫远程代理。]
齐少爷和尹小姐书信来往好久了,齐少爷记不得以前写过什么良言美句,书童会意,把保存的书信拿了出来参考。[ 书童就好比缓存代理 ]
齐家毕竟是大户人家,也指望齐少爷他日金榜题名,齐老太太天天来检查齐少爷的读书情况。这天少爷溜出去与尹小姐私会,书童穿了少爷的衣服在窗后装模作样,老太太看到窗影很高兴。 [ 虚拟代理 ]
书童身材和少爷还是比较相似的,少爷毕竟是老爷的儿子,萧峰和萧远山也很难分清的。 这天,齐老爷有点喝高了,想去留香院找小春,想起了儿子(老不正经!),于是和书童(正扮演少爷)说: 今天你扮成我,你的事过几天我做主。 于是书童又穿上老爷的衣服,贴上胡子,还有模有样。 [ 装饰者模式: 川剧《变脸》 == 本体就是那个,但外表已经改变。 ]
代理模式: 为另一个对象提供一个替身或占位符以控制对这个对象的访问。
[ 使用代理模式创建代表(representative)对象,让代表对象控制某对象的访问,被代理的对象可以是远程的对象 、创建开销大的对象或需要安全控制的对象。 ]
|
|_____> 远程代理控制访问远程对象;
|_____> 虚拟代理控制访问创建开销大的资源;
|_____> 保护代理基于权限控制对资源的访问;
设计原则: 类应该只有一个改变的理由。
模式对比:
· 装饰者 ── 包装另一个对象,并提供额外的行为;
· 外观 ── 包装许多对象以简化它们的接口;
· 代理 ── 包装另一个对象,并控制对它的访问;
· 适配器 ── 包装另一个对象,并提供不同的接口;
Head First 设计模式: 第十二课 复合模式
模式的模式:
§ 模式通常被一起使用,并被组合在同一个设计解决方案中。
§ 复合模式在一个解决方案中结合两个和多个模式,以解决一般或重复发生的问题。
MVC (Model-View-Controller) : 模型利用“观察者”让控制器和视图可以随最新的状态改变而更新。另一方面,视图和控制器则实现了“策略模式”。控制器是视图的行为; 视图内部使用组合模式来管理显示组件。
o 模型使用观察者模式,以便观察者更新,同时保持两者之间的解耦。
o 控制器是视图的策略,视图可以使用不同的控制器实现,得到不同的行为。
o 视图使用组合模式实现用户界面,用户界面通常组合了嵌套的组件,像面板、框架和按钮。
o 这些模式携手合作,把MVC模式的三层解耦,这样可以保持设计干净又有弹性。
o 适配器模式用来将新的模型适配成已有的视图和控制器。
复合模式: 复合模式结合两个或以上的模式,组合一个解决方案,解决一再发生的一般性问题。( MVC 结合观察者模式、策略模式、组合模式)
Head First 设计模式: 第十三课 与设计模式相处
“每一个模式描述了一个在我们周围不断重复发生的问题以及该问题解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动。” ── 建筑家 Christopher Alexander
模式 是在某情境 (context) 下,针对某问题的某种解决方案。
· 情境 就是应用某个模式的情况。这应该是会不断出现的情况。
[ 我要如何准时上班? ]
· 问题 就是你想在某情境下达到的目标,但也可以是某情境下的约束。
[ 我将钥匙锁在车里了。]
· 解决方案 就是你所追求的: 一个通用的设计,用来解决约束,达到目标。
[ 打破窗户,进入车内,启动引擎,然后开车上班。]
· 成本 解决方案所花费的才力 (财力)。
[ 窗户的价值。]
模式是解决问题的方法,用于不用无所谓; 但当我们应用模式时,就应该考虑怎么才能更好的解决问题 (反之,去除模式)。
最后的模式连连看
1. 装饰者 ── 包装一个对象,以提供新的行为。
2. 状态 ── 封装了基于状态的行为,并使用委托在行为之间切换。
3. 迭代器 ── 在对象的集合中游走,而不暴露集合的实现。
4. 外观 ── 简化一群类的接口。
5. 策略 ── 封装可以互换的行为,并使用委托来决定要使用哪一个。
6. 代理 ── 包装对象,以控制对此对象的访问。
7. 工厂方法 ── 由子类决定要创建的具体类是哪一个。
8. 适配器 ── 封装对象,并提供不同的接口。
9. 观察者 ── 让对象能够在状态改变时被通知。
10. 模板方法 ── 由子类决定如何实现一个算法中的步骤。
11. 组合 ── 客户用一致的方式处理对象集合和单个对象。
12. 单件 ── 确保只有一个对象被创建。
13. 抽象工厂 ── 允许客户创建对象的家族,而无需指定他们的具体类。
14. 命令 ── 封装请求成为对象。