`
wangxiaohigh
  • 浏览: 1429839 次
文章分类
社区版块
存档分类
最新评论

《设计模式精解》学习笔记

 
阅读更多

一、首先介绍一下常用的面向对象术语:

抽象类:为一组概念上相似的类定义方法和公共属性。抽象类绝对不能被实例化

属性:与一个对象相关联的数据(数据成员)

封装:任何形式的隐藏。对象对它们的数据进行封装,抽象类对它们派生出的具体类进行封装。

继承:一种类特殊化的方式,用于联系派生类和它们的抽象类。

对象:负有责任的一个实体。一个特定的、自包含的容器,其中包含数据和操作这些数据的方法,一个对象的数据对于其他对象是隐藏的。

多态:相关的对象按照各自类型来实现方法的能力。

二、Façade(外观)模式

为了子系统中的一组接口提供了一个一致的界面,Façade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。可以说是希望简化现有系统的使用方法,让客户与子系统(或底层系统)绝缘。

Façade模式的变体有:1、减少客户必须处理的对象数量;2、用新的程序对现有功能进行补充;3、一个封装层。

Façade模式的命名来源是因为它在原始系统的前面建造了一个新的前端接口(一个“外观”),其适用于以下情况:

1、不需要使用一个复杂系统提供的所有功能,并且可以创建一个新的类来包容访问原有系统所使用的所有规则。

2、希望包装或隐藏原有系统。

3、希望使用原有系统的功能,并且希望增加一些新的功能。

4、编写一个新的类的代价小于让所有人学会使用复杂系统或在未来维护整个系统。

三、Adapter模式

Adapter模式的意图是将一个类的接口转换成客户希望的另外一个接口。Adapter模式使原本由于接口不兼容而不能一起工作的那些类可以一起工作。

Adapter模式让现存的对象适应新的类结构,而不它们的接口限制。其实现了将现存的类包含在另一个类中,包容类与需要的接口相匹配,并调用被包容类方法。举例如下图:

Adapter模式让我在进行设计时不必担心现存类的接口问题,如果我拥有一个类,它又有我需要的功能,那么至少在概念上我知道我可以用Adapter模式来为它提供合适的接口。

表1给我们的结论是:Façade模式简化接口, Adapter模式将接口转换成另一个接口。

四、Bridge模式(难点)

Bridge模式的意图是将抽象部分与它的实现部分分离,使它们都可以独立地变化。这里的实现部分是指“抽象类的对象和用来实现抽象类的派生类的对象”。

图3中,左边体系包含了抽象部分的变化点,右边体系包含了如何实现抽象部分的变化点。Bridge模式把实现部分看成对象外部的、被对象使用的某种东西。此例中,即使是有好几个类,系统同时处理的只有三个对象,如下图4.

在学习Bridge模式过程中,应该遵循处理变化的基本策略:发现并封装变化点;优先使用对象组合而非类继承。

五、Abstract Factory抽象工厂模式

抽象工厂模式的意图是“提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类”。(协调对象的实例化)

1、Switch语句可能指出对抽象的需要:switch语句常常标志着对多态性为的需要,存在着放错地方的责任,所以我们需要考虑用一种更普适的解决方案代替switch语句,比如抽象、将责任交给另外的对象等。

2、用抽象来代替switch语句。通过定义一个表示“工厂”概念的抽象类将变化点封装在一个类中。

3、在Abstract Factory模式中,客户对象只知道“向谁请求需要的对象”和“如何使用这些对象”;Abstract Factory类通过“为每种不同类型的对象定义一个方法”来指定“哪些对象可以被实例化”。典型情况下,一个Abstract Factory对象将针对每种必须实例化的对象拥有一个方法;具体工厂指定哪些对象将被实例化。

六、设计模式的原则和策略

1、开放-封闭原则

这条原则的意思是:模块、方法和类应该对扩展开放,而对更改封闭。即是我们可以在不修改代码的前提下对我们的软件进行扩展。

Eg:在Bridge模式中就很有可能在不修改任何现存的类的前提下加入新的实现部分,即对软件进行扩展。

2、从场景进行设置的原则(Bridge和Abstract Factory都是好例子)

Alexeander告诉我们要从场景进行设计,在设计我们的片段出现的细节之前先创建整体视图。Eg:如果我在编写一个软件,它需要在不同类型的硬件上画出几何形状,因此需要不同的实现部分,我会使用Bridge模式,Bridge模式告诉我几何形状将通过一个公共接口使用我的实现部分(即画图程序),从场景进行设计意味着我应该首先观察形状的需求,即我必须画什么,这些形状将确定我的实现部分需要的行为,如画线、画圆等。

通过从场景进行设计,这些模式让我可以预见到可能的变化点,因为我已经将我的系统划分成了行为良好的类,因此变化更容易得到适应。

Adapter模式也阐述了从场景进行设计的原则,因为它几乎总是出现在某个场景中。根据定义,Adapter模式被用于将一个现存的接口转换成另一个接口。Adapter模式可以用来将一个类适配成某个模式需要表示的角色。

从场景的角度,Façade模式与Adapter模式非常相似。典型情况下,Façade模式是在其他模式或类的场景中定义的,即是我必须等待,直到我发现谁需要Façade模式来对自己的接口进行设计。

3、包容变化的原则

Bridge模式中的实现部分各不相同,但都可以通过一个通用接口被访问。系统可以接纳新的实现部分,只要它也使用这个通用接口来实现。

Abstract Factory模式包容了“哪些系列或家族的对象可以被实例化”中的变化,其本身的概念(实现为一个接口)隐藏了“如何创建对象”的变化。此模式中,工厂对象的接口不会改变,只有它的实现方式会改变。

Adapter模式是一个工具,用以将完全不同的对象适配在一起,并给它们一个通用的接口。

典型情况下,Façade模式不包容变化。但是,很多案例中使用Façade模式与一个特定的子系统协同工作,然后当另一个子系统出现时,新的子系统的Façade也会用相同的接口创建出来,这个类是Façade模式和Adapter模式的结合物,其首要动机是简化,但现在有附加的约束:与前面已经投入使用的接口一致,这样客户对象都不需要修改,这样使用Façade模式就隐藏了“正在使用的子系统”的变化。

七、Strategy(策略)模式

Strategy模式的意图是:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使算法可独立于使用它的客户而变化。Strategy模式建立的基础原则:

1、 对象拥有责任

2、 这些责任的不同的特定实现通过使用多态来表现

3、 需要将几个不同的实现按照相同的算法来管理(概念上)

4、 一个好的设计经验:将问题领域中发生的行为彼此分离。这使得我们可以改变对某一行为负责的类,而不会对其他行为产生不好的影响。

Strategy模式需要根据发出请求的客户或被处理的数据对算法作出选择,如果你只是拥有一些不发声色变化的算法,就不需要Strategy模式。Strategy的具体实现:让使用算法的类包含一个抽象类,抽象类中有一个抽象方法指定如何调用算法,每个派生类根据需要实现算法。

八、Decorator(装饰)模式

Decorator模式按照所需的合适顺序将所需的功能串在一起,从而实现对它们的控制,Decorator模式将功能链的动态构造与使用功能链的客户相分离。它的意图是:动态地给一个对象添加一些额外的职责。其效果是:可以创建以decorator对象(负责新功能的对象)开始的一条对象“链”,并结束于最初的对象。它的常见用途是在流式输入/输出中。

Decorator模式是为现有的功能动态添加附加功能的一种方法。实际情况要求创建一条对象链来提供需要的行为。对象链的第一个对象被客户对象调用,客户对象不关心对象链的创建,通过保持对象链的创建与使用的相互独立,添加功能的新需求不会对客户对象造成影响。

九、Singleton(单件)模式和Double-Checked Locking(双重检查锁定)模式

Singleton模式和Double-checked Locking模式(singleton模式的变体)都用以确保一个特定的类只有一个对象被实例化。这个两个模式之间的区别是:Singleton模式用于单线程应用程序,而Double-checked locking模式用于多线程应用程序。

Singleton模式的意图是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。它的工作方式是:拥有一个特定的方法,这个方法被用于实例化需要的对象。1)当这个方法被调用时,它检查这个对象是否已经被实例化。如果对象已经被实例化,这个方法仅仅返回这个对象的一个引用;如果对象尚未实例化,这个方法将对象实例化并返回这个新的实例的引用。2)为了确保这是创建这个类型的对象的惟一途径,我在这个类中将构造函数定义为protected或private。

Singleton模式让对象对自己负责。例如:我创建了一个方法getInstance,这个方法将最多实例化一个USTax对象,此外通过将构造函数定义为private(这意味着其他对象不能访问它),Singleton模式防止了其他任何人直接实例化USTax对象。C++代码如下:

class USTax{

private: static USTax* instance;

private: USTax();

public: static USTax* getInstance();

}

USTax* USTax::getInstance = 0;

USTax* USTax::getInstance(){

if(instance == null) instance = new USTax();

return instance;

}

Double-checked Locking模式的特点:1)通过用另一个条件检查限制对new的调用,非必需的锁定得到了避免。2)支持多线程环境。C++代码如下:

class USTax: public CalcTax{

private: static USTax* instance;

private: USTax();

public: static USTax* getInstance();

}

USTax* USTax::getInstance = 0;

USTax* USTax::getInstance(){

if(instance == 0){

//do sync here

if(instance == 0){ instance = new USTax;}

}

return instance;

}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics