看书时的笔记,加一些总结,没有排版直接贴出来了,不喜请勿喷。
Q: Strategy Pattern
A:
duck父类派生子类
-> 问题:有些duck不应该会fly(),但父类有fly()方法被继承
-> fly()方法变成接口(这里指java接口),由各个duck的类去实现
-> 问题:代码得不到重用,修改困难(同时修改多个子类)
Design Principle
Identify the aspects of your application that vary and separate them from what stays the same.
Program to an interface(基类或java接口), not an implementation.
Favor composition over inheritance.
组合使得我们能在运行时动态改变行为
-> fly()方法变成interface(指基类或java接口),由各个具体FlyBehavior类去实现,然后FlyBehavior作为duck类的一个成员(组合),delegate给FlyBehavior去fly()
* 能够在运行时动态改变fly的行为
mine:
本来是一个虚函数
变成了一个接口作为成员变量(组合而不是继承),然后各个类有对应的该接口的实现作为变量的值
能够在运行时动态改变具体实现
具体实现可以复用
1. encapsulate what varies
2. program to an interface
3. composition
4. 开放闭合
Q: Observer Pattern
A:
Subject & Ovserver
Observable
成员变量:
ArrayList<Observer>
bool changed
成员函数:
addObserver()
deleteObserver()
notifyObserver()
setChanged()
Observer
成员函数:
update()
可使用推数据和拉数据两种方式
在subject中有个setChanged(),当changed为true时,对observer发送通知
推数据:
public void update(Object arg) {
// arg里包含了subject送来的数据
}
拉数据:
public void update(Observable obs, Object arg) {
// observer主动调用obs.getData(...)获取想要的数据
}
loose coupling
two objects can interact, but have very little knowledge of each other.
在这里subject只知道observer实现了observer接口
Design Principle
Strive for loosely coupled desingns between objects that interact.
Example: Java Swing 按钮事件
Q: Decorator pattern
A:
Doesn't alter the interface, but adds responsibility.
Design Principle
Classes should be open for extension, but closed for modification.
alternative to subclassing
Decorators have the same supertype as the objects they decorate.
(we're using inheritance to achieve the type matching, but we aren't using inheritance to get behavior)
(we are acquiring new behavior not by inheriting it from a superclass, but by composing objects together.)
通常装饰者模式采用抽象类,在java中可以使用接口
Component
method()
ConcreteComponent
method()
Decorator (extends Component)
method()
ConcreteDecorator
拥有Component成员变量
method() (对Component成员变量的method增加一些行为)
Example: Java IO
mine:
代替subclassing的一种方法,虽然不够通用
有点像函数式编程,跟python的decorator其实本质是一样的
缺点:
1. 很多decorator的small classes
2. 若函数依赖具体的types则不适用
3. 实例化比较麻烦
1. encapsulate what varies
2. program to an interface
3. composition
4. 开放闭合 (已有的使用Component的代码不用改变,对修改闭合;对增加Decorator开放)
Q: Factory pattern
A:
remove the concrete instantiations from our client code
1. Simple Factory方式:
encapsulate object creation
SimpleFactory
CreateProduct()
创建Product,可能是以String参数指定要创建的Product子类
该方法常声明为static
Product
派生出Product1,Product2,...
Client
成员变量:
SimpleFactory
由构造函数传进来
缺点:
(1) 要是想在不同情况下创建的Product不一样,同一个SimpleFactory做不到,如NYChessPizza vs. CNChessPizza,虽然可以创建不同的SimpleFactory,但存在问题(2)
(2) 要是想Product的使用方式也不被改动,则看下面Factory Method
2. Factory Method
client是抽象类,真正的对象在子类创建
decouple the client code in the superclass from the object creation code in the subclass
decouple the implementation of the product from its use
encapsulate object creation
甚至可以定义Default factory method从而有默认值可以用 pp.135
give you the flexibility to vary the products you're creating (SimpleFactory做不到,如NYChessPizza vs. CNChessPizza)
Creator (abstract)
factoryMethod() (abstract)
由具体的creator(也是使用Product的类)去继承,并实现factoryMethod,创建不同的派生自Product的类
可以有多个不同的factoryMethod
可以为parameterized factory method
give you the flexibility to vary the products you're creating (SimpleFactory做不到,如NYChessPizza vs. CNChessPizza)
其他的methods可以是implements,但只依赖Product接口而不是具体的Products,真正创建了哪个具体的Product取决于子类的factorMethod()实现 (且各个ConcreteCreator不能自己随意改动,这是SimpleFactory做不到的)
Product (abstract)
派生出具体的product,由不同的具体的creator去创建
特点:
1. 一个工厂方法只创建一个Product,若存在多个并列关系的Product,则抽象工厂更适用
2. Product的使用可以在基类里定义好,不依赖于具体实现,从而保证其不被改动
3. Abstract Factory Pattern
AbstractFactory (interface)
CreateProduct1()
CreateProduct2()
由具体的factory去继承并重写CreateProduct函数,创建不同的具体的Product
抽象工厂的方法其实就是工厂方法
AbstractProduct1 (interface)
派生出具体的product1,由不同的具体的factory去创建
AbstractProduct2 (interface)
派生出具体的product2,由不同的具体的factory去创建
...
Client
成员变量:
AbstractFactory
由构造函数传进来
特点:
1. 若存在多个并列关系的Product,则抽象工厂更适用
2. 抽象工厂中的CreateProduct() interface其实就是工厂方法
3. 抽象工厂没有工厂方法带来的限定Product使用方法的效果。
Design Principle:
Dependency Inversion Principle: Depend upon abstractions. Do not depend upon concrete classes.
(在这里就是工厂方法创建的是Product接口/父类,而不是具体的Product子类)
(与Program to interface有点类似)
(High-level components should not depend on low-level components, they should both depend on abstractions.)
Guidelines:
1. No variable should hold a reference to a concrete class.
2. No class should derive from a concrete class.
3. No method should override am implemented method of any of its base classes.
1. encapsulate what varies
2. program to an interface (抽象工厂是interface,要创建的product也是interface)
3. composition (抽象工厂就是作为类成员)
4. 开放闭合 (工厂方法限定Product的使用,对修改闭合)
5. 依赖倒置(即依赖于抽象类/interface)
mine 工厂模式总结:
书里的例子的Product是指pizza,这些pizza有2个维度的区别:1. 种类(如chess, veggie); 2. 区域(如NY, Chicago)
对于只有一个维度差异的Product,如不同种类的pizza,Simple Factory就可以解决,也就是所谓parameterized factory
但当出现2个维度时,Simple Factory就不够适用了,比如要创建NYSimpleFactory,ChicagoSimpleFactory等
这些SimpleFactory作一下自底向上的抽象,其实就是抽象工厂,比如不同区域对应一个抽象工厂的Concrete class,然后每个工厂创建不同种类的pizza(通过参数化的工厂方法)。
其实抽象工厂也可以简单地创建一个维度差异的Product,就是不同的Concrete class创建不同的pizza
但抽象工厂更适用于多个并列关系的Product都要创建的情况,所以书里没有讨论上面的情况,而是以ingredient的创建来作为例子,因为各种ingredient间是并列关系。
而Pizza是作为抽象工厂的cilent,某个种类的pizza的区域特征是通过该区域对应的ingredient factory的成员变量来确定的。
同时抽象工厂没有工厂方法带来的限定Product使用方法的效果。
书里解决2个维度差异的方法是使用工厂方法,即工厂方法是参数化的创建不同种类的pizza,然后不同的工厂方法的实现对应不同的区域差异。
使用工厂方法的另一个好处是,可以在基类里限定pizza的使用方法,使其不依赖于具体的pizza种类,防止代码被随便修改。这也算是对修改闭合的例子吧。
最后书里把工厂方法与抽象工厂结合起来
pizza的区域是由不同的工厂方法的实现确定的,pizza的种类是工厂方法的参数。
当实现工厂方法时,Pizza是作为抽象工厂的cilent,某个种类的pizza的区域特征由该区域对应的ingredient factory成员亦是的实现来确定
Q: Singleton
A:
多线程
1. 使用new
多线程情况下new之前两次判空并加锁,client原子性地获得instance并操作
volatile static Singleton *instance;
static Singleton *GetInstance()
{
if (NULL == instance)
{
lock();
if (NULL == instance)
{
instance = new Singleton();
}
unlock();
}
return instance;
}
// 要避免CPU乱序执行,加barrier() <<修养>>
2. 使用static的饿汉模式
可以增加Lock()方法,在其他方法中检查锁,client可以获得instance,但调用方法时,该操作的原子性由类自身保证
优点:简洁,没有CPU乱序执行的问题
缺点:
不能使用时才构造
static Singleton instance; 不会出现初始化顺序不确定的情况吗?
会呀,所以不能依赖其他类的全局变量/静态变量的初始化,否则会有问题
3. 使用static局部变量
http://stackoverflow.com/questions/449436/singleton-instance-declared-as-static-variable-of-getinstance-method
C++11中是线程安全的
C++03中使用g++是安全的,否则很可能不安全
http://stackoverflow.com/questions/335369/finding-c-static-initialization-order-problems#335746
SomeBaseClass &SomeClass::GetInstance()
{
#ifdef _WIN32
Start Critical Section Here
#elif defined(__GNUC__) && (__GNUC__ > 3)
// You are OK
#else
#error Add Critical Section for your platform
#endif
static SomeClass instance;
#ifdef _WIN32
END Critical Section Here
#endif
return instance;
}
缺点:不像二次判空,这样加锁对性能会有点消耗
(其实可以恶心地绕开,如定义一个成员变量是类对象指针,初始化为空,当调用GetInstance()时置为指向该static类对象,此时就有二次判空了)
Q: Command Pattern
A:
对某些类的方法调用进行统一封装与抽象
多个不同类的方法希望用同一方式调用时使用
or
When you need to decouple an object making requests from the objects that know how to perform the requests
Command类(具体的类,而不是Command interface)将
1. Receiver
2. 要调用Receiver的actions
封装起来,对外提供统一接口execute()
Invoker类就是调用Command类的execute()接口
Client创建Command类的具体实现
从另一个角度看,一个Command也可以看作一个Request/Job
于是就有对应的Job queue,然后每个woker取出来调用一个execute()方法就完了
1. program to interfaces (Invoker类只依赖Command接口)
2. composition (Receiver是Command实现的成员)
3. 依赖倒置(依赖于Command interface)
4. 开放闭合(Invoker的代码对修改闭合,Command类的具体实现对添加新的Command开放)
5. 松耦合 (Invoker只知道Command的execute()方法)
Q: Adaptor
A:
Object Adaptor:
因为client只依赖interface,所以可以创建一个interface的adaptor类将其他类型的interface(不一定是实现从而更“通用”)wrap在里面然后模仿client依赖的interface的行为
client (依赖interface1)
interface1
adaptor (将interface2适配为interface1)
interface2或更多个
client与adaptor是decoupled的,彼此对对方一无所知
adaptor可能将多个interfaces适配成client想要的那一个interface
若client同时有新旧代码使用了新旧interface,可考虑Two Way Adaptor,同时实现新旧interface (即Adaptor可以同时实现多个interface)
adapter不仅可以适配adaptee,还可以适配它的子类
1. 开放闭合 (对interface2的改变,client不需要修改,对修改闭合; 对增加新interface的支持开放,只要adaptor适配一下就可以了)
2. composition (Adaptor中有interface2的成员)
3. program to interface (client只依赖interface1)
Class Adaptor:
client
target class
adaptee class
adatper class (inherits target class && adaptee class)
adapter只可以适配adaptee,不可以适配它的子类
Don't have to reimplement entire adaptee (??????)
Q: Facade
A:
take a complex subsystem && implement a facade class to provide more reasonable interface
facade don't "encapsulate" the subsystem classes. It provides a simplified inteface while still exposing the full functionality of the system.
client依赖于facade而不是subsystem
decouple client implementation from any one subsystem
同一个subsystem可以实现多个facade
1. subsystem同一层次上不同的simplified interfaces
2. subsystem的不同层次上的facade
Design Principle: Least Knowledge
Take an object, 当写该object的method时,
invoke methods that belong to:
1. methods of the object itself;
2. Objects passed in as a parameter to the method;
3. Any object the method creates or instantiates
4. methods of any components of the object
Not to call
methods on objects that were returned from calling other methods.
优点:
reduce dependencies
reduce software maintenance
缺点:
more wrapper classes
increased complexity and development time
decreased runtime performance
1. 开放闭合 (client依赖facade,subsystem改变时client不需要修改)
2. composition (facade class has access to all the components of the subsystem)
3. Least Knowledge (若依赖多个类,通过中间层将二者隔离; Reduce the number of classes dependent on)
mine:
client直接依赖subsystem的话,subsystem要修改时要改动client,使得整个系统难以维护
通过facade作为二者的中间层,client依赖facade,facede隐藏了subsystem的细节,使得subsystem要修改时不用改动client
subsystem修改时,要修改facade工作量也不少,但相比client直接依赖subsystem,在这里client已经不需要再修改了
3个相似又侧重点不同的Design Priciple:
program to interface
依赖倒置 (依赖很多类时,把这些类抽象为接口)
Least Knowledge (若依赖多个类,通过中间层将二者隔离; Reduce the number of classes dependent on)
2个相似的Design Priciple
loose couple (只依赖接口及某个方法)
Lease Knowledge (依赖尽量少的类)
Q: template patten
A:
Design Principle:
Hollywood Principle: Don't call us, we'll call you.
lower-level component一般不调用higher-level component的方法,除非是继承过来的,避免循环依赖
有点类似依赖倒置原则,只是这里是子类重写抽象类的某些方法,client依赖抽象类而不是依赖倒置那里的例子一样依赖interface
mine:
就是自底向上的抽象
具体的类是抽象类的子类
在这方面有点类似工厂方法模式,而不是以另一个类对象作为成员(composition)的抽象工厂模式
类中有template method
template method表示的是一个algorithm的template
template method是由多个methods实现的
primitiveOperation()
concreteOperation()
hook method
1. 提供默认行为,子类可以自行决定是否重写该hook
2. 在某些行为前/后,子类可以做动作
template method也可能是一个Static method(或者是一个函数),但它要求使用到的类实现了某个方法(松耦合)
工厂方法是template method的特例 (可能是指工厂方法是整个algorithm的其中一个步骤,行为由子类决定)
1. 松耦合 (可以只需要类对象实现了某个方法,如java中的sort()函数)
Q: Iterator
A:
Design Principle:
A class should have only one reason to change.
1. encapsulate what varies (client要做的是对不同的数据结构进行遍历,封装起来就是使用Iterator)
2. program to interface (client只依赖Iterator接口)
3. 开放闭合 (原来的代码只需要增加createIterator()接口,依赖Iteartor接口的client从此对修改闭合)
Q: Composite
A:
树状结构的表示 (有点像FP)
但通过抽象类,内部结点与叶子结点都是子类,client只依赖子类,从而对client透明
违反Single Responsibility原则,换来对client透明
要遍历树可以简单递归
Example: 编译器中AST的遍历
但要建一个iterator就需要维护一个Stack
Q: State
A:
与Strategy模式类似,但client知道Strategy的composition的类,而State类是对client透明的
1. encasulate what varies (将各个状态以类封装起来)
2. program to interface (Context依赖的是State的接口/抽象类)
3. composition (State是作为Context的成员存在的,从而可以方便改变状态)
4. 开放闭合
(如果状态转换在State中完成,则增加新状态时不需要改变Context,Context对修改闭合,但可能改变一些State类)
(如果状态转换在Context中完成,则增加新状态时不需要改变原来的State的类,但要改变Context)
Q: proxy
A:
remote proxy
virtual proxy
protection proxy
proxy有点像decorator,但使用目的与作用不一样
proxy也有点像adaptor
可以通过factory使得proxy对client透明
1. program to interface (RealSubject与proxy都实现同一接口,然后client只依赖接口)
2. composition (RealSubject是proxy的一个成员,delegate给它进行实质的行为;proxy/RealSubject一般都是client的成员,而且client只依赖接口,从而可以在proxy与RealSubject中切换,client并不需要修改)
3. 开放闭合(proxy/RealSubject一般都是client的成员,而且client只依赖接口,从而可以在proxy与RealSubject中切换,client并不需要修改)
Q: MVC
Observer pattern
Model是Observable,View与Controller是Observer
因此Model不知道View与Controller
而View与Controller依赖Model的interface
但这里View与Controller是知道Model的接口的,而没有Observer pattern里“推”数据那么“松耦合”
View知道Model的接口去“拉”数据
Controller知道Model的接口,但这里Controller不是作为Observer被更新后“拉”数据,而是直接调用Model的接口
甚至更进一步,View与Model的创建与初始化都是通过Controller的
Strategy pattern
Controller是View的behavior
因此View依赖Controller的interface很正常
但Controller中也有View的引用作为成员(且View不是接口),这里跟之前Strategy有点不一样
甚至更进一步,View的创建、初始化及start() stop()设置都是通过Controller的,这里就不是Strategy的部分了???
(也就是说,Controller具体类是可能依赖View的)
View中的各个组件是以Composite的形式组织的
Use an adaptor to adapt a model to work with existing controllers and views.
要复用View,只需要一个Adaptor去将新的Model适配到旧的Model,然后再新建一个Controller
The View doesn't alter the model, that's the controller's job, all it does is use its state.
Example:
Database, JSP, Servlet
Servlet接收到http请求就像用户点了View了以后由View delegate到Controller
Servlet更新Jsp就像Controller更新View
JSP(View)的更新是通过Servlet(Controller)而不是直接通过Model的
不是原来pattern的地方:
Controller知道Model的接口,但这里Controller不是作为Observer被更新后“拉”数据,而是直接调用Model的接口
甚至更进一步,View与Model的创建与初始化都是通过Controller的
Controller中也有View的引用作为成员(且View不是接口)
甚至更进一步,View的创建、初始化及start() stop()设置都是通过Controller的
(也就是说,Controller具体类是可能依赖View的)
View要修改Model要通过delegate给Controller,Controller直接调用Model的接口
Controller有可能改变View,也可以直接调用Model的接口
Model通过Observer pattern来update View,不走Controller
1. Program to interface (View与Controller依赖ModelInterface,View依赖ControllerInterface,但View是具体的类)
2. composition
相关笔记
《深入浅出设计模式(影印版)》热门书评
-
Head First Design Patterns让设计模式走向大众
24有用 1无用 红眼睛阿义 2006-02-08
本影印版刚拿到手,感觉沉甸甸的,第一印象就不错,网上评价也很好。恰巧快到春节,于是在书架一大堆的书籍中,我只选择这本比较厚重的,塞到我的行李包中。翻开一看,真如Erich Camma所说,简直欲罢不能.本书是Oreilly的Head First系列中的一本,本系列书籍的特点是采用大量的插图、图例来进...
-
入门看这本书的话很不错
16有用 3无用 Luffy Lee 2009-11-14
写得很有趣,图文并茂,比起四人帮的那本,好懂了不知道多少倍。计算机世界的head first系列让我想起了阿呆系列,话说新的一集the big bang theory里面lennerd学习橄榄球的时候也有一本阿呆啊,哈哈,跑题了不过只看书学明白设计模式是不可能的,这些只是前人的总结,我们唯有实践实践...
-
值得每一位程序员阅读的书
10有用 0无用 曹操 2009-04-02
读这本书不仅仅是学习知识,而是在学习一种思考的方法,学习一种认知的技巧,学习一种成长的阶梯。总之,用你闲暇的时间来读这本书,并不亚于你专注的工作或学习。...
-
深入浅出
9有用 0无用 Jarod 2006-09-13
这本书没有辜负这个名字。作者说他们把原本属于设计模式的来源还给设计模式的学习和应用过程。他们确实这样做到了。让读者能够从生活中的例子随着论述的展开,逐步深入设计模式的核心,这个确实是在目前的设计模式教程里面比较少见的,这个也是这本书能够不负其初衷的重要原因。...
-
拿了Jolt大奖的东西
7有用 1无用 yasker 2006-12-25
看书之前本来仰慕已久,不过看完了稍显失望。怎么说呢,这种非常轻松的东西倒是很好,就是有点过于分散了点。另外有的模式对我来说简直是惊世骇俗,但是有的实在是非常符合一般规律,能够直接根据OO的原则想出来的。还有一点不太满意就是习题有的有点弱智,有的又跑得太远……这方面规划似乎不是太好。每章的总结倒是非常...
书名: 深入浅出设计模式(影印版)
作者:
出版社: 东南大学出版社
原作名: Head First Design Patterns
出版年: 2005-11
页数: 638
定价: 98.00元
装帧: 平装
丛书: O'Reilly深入浅出系列
ISBN: 9787564101657

