设计模式总结 - 创建模式,结构模式,行为模式

注:

文档内容基本上来自于网上,并加上自己的理解而成。有的觉得网友总结得非常好,就完全照搬下来,供学习之用。然而,有的摘抄并没有加上原链接和出处,请谅解。

一, 创建型模式 (Creational Patterns)

Creational design patterns are composed of two dominant ideas. One is encapsulating

knowledge about which concrete classes the system use. Another is hiding how instances of these concrete classes are created and combined.

即创建型模式有两部分主要思想:1. 对系统所要使用的具体类的封装,

2. 隐藏这些具体类的创建和组合过程。

创建模式强调在具体情况下对像实例的创建机制,通过恰当的对象创建机制,可以减少设计的麻烦和程序的复杂性。

二, 结构型模式 (Structural Patterns)

From Wikipedia:

In , structural design patterns are that ease the design by identifying a simple way to realize relationships between entities.

这一类的模式关心实体(类或者对象)之间如何组织起来,以形成更大的结构. 主要使用继承来组织接口或实现.

三, 行为型模式 (Behavioral Patterns)

From WIkipedia:

In , behavioral design patterns are that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication.

这一类的模式关心的是算法以及对象之间的任务分配. 行为设计模式识别出对象之间的共同的通信模式,并实现这种模式。这样就可以提高这类通信的灵活性。

设计模式在粒度和抽象层次上各不相同。由于存在众多的设计模式,所以我们可以用一种方式将它们组织起来。这里,我们根据两条准则对模式进行分类,如下表所示:

第一是目的准则,即模式是用来完成什么工作的。模式依据其目的可分为创建型( Creational)、结构型( Structural)、或行为型( Behavioral )三种。创建型模式与对象的创建有关;结构型模式处理类或对象的组合;行为型模式对类或对象怎样交互和怎样分配职责进行描述。

下来了。第二是范围准则,指定模式主要是用于类还是用于对象。 类模式处理类和子类之间的关系,这些关系通过继承建立,是静态的,在编译时刻便确定

对象模式处理对象间的关系,这些关系在运行时刻是可以变化的,更具动态性。从某种意义上来说,几乎所有模式都使用继承机制,所以“类模式”只指那些集中于处理类间关系的模式,而大部分模式都属于对象模式的范畴。

创建型类模式将对象的部分创建工作延迟到子类,而创建型对象模式则将它延迟到另一个对象中。

象的组装方式。 结构型类模式使用继承机制来组合类,而结构型对象模式则描述了对

行为型类模式使用继承描述算法和控制流,而行为型对象模式则描述一组对象怎样协作完成单个对象所无法完成的任务。

还有其他组织模式的方式。有些模式经常会被绑在一起使用,例如, Composite(组合模式)常和Iterator(迭代器模式)或Visitor(访问者模式)一起使用;有些模式是可替代的,例如, Prototype(原型模式)常用来替代Abstract Factory(抽象工厂模式);有些模式尽管使用意图不同,但产生的设计结果是很相似的,例如, Composite(组合模式)和Decorator(装饰模式)的结构图是相似的。

还有一种方式是根据模式的“相关模式”部分所描述的它们怎样互相引用来组织设计模式。下图给出了模式关系的图形说明。

显然,存在着许多组织设计模式的方法。从多角度去思考模式有助于对它们的功能、差异和应用场合的更深入理解。

六大设计原则:

开闭原则:一个软件实体应该对扩展开放对修改闭合。

里氏代换原则:任何能使用父类的地方一定能使用子类。

依赖倒转原则:要依赖于抽象不要依赖于实现。或者是抽象不应该依赖与细节,细节应该依赖于抽象。

合成聚合复用原则:尽量使用合成聚合而不是继承去实现复用。

迪米特法则:一个软件实体应该尽可能少的与其它实体发生相互作用。迪米特法则(Law of

Demeter)又叫作最少知识原则(Least Knowledge Principle 简写LKP),就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。英文简写为: LoD.

接口隔离原则:应当为客户提供尽可能小的单独的接口而不应该提供大的综合性的接口。

 

第二篇:设计模式总结 - Template模式

注:

文档内容基本上来自于网上,并加上自己的理解而成。有的觉得网友总结得非常好,就完全照搬下来,供学习之用。然而,有的摘抄并没有加上原链接和出处,请谅解。

Template模式

一、 模板方法(Template Method)模式 准备一个抽象类,将部分逻辑以具体方法以及具体构造子的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模版方法模式的用意。

应用场景:

1. 同一类系统消息有公共部分,具体的各个消息所不同的部分在子类中实现。

2. 图片处理中,jpg, rmp,png也好,他们可能打开文件、读取文件的方法都一样,然而可能处理方法不一样

3. 数据库中连接、打开、关闭和使用 可能只有连接不一样,其他的可能一样。这个时候就可以用模板模式

很多人可能没有想到,模版方法模式实际上是所有模式中最为常见的几个模式之一,而且很多人可能使用过模版方法模式而没有意识到自己已经使用了这个模式。模版方法模式是基于继承的代码复用的基本技术,模版方法模式的结构和用法也是面向对象设计的核心。

模版方法模式需要开发抽象类和具体子类的设计师之间的协作。一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤。代表这些具体逻辑步骤的方法称做基本方法(primitive method);而将这些基本法方法总汇起来的方法叫做模版方法(template method),这个设计模式的名字就是从此而来。

二、 模版方法模式的结构

模版方法模式的静态结构如下图所示。

这里涉及到两个角色:

抽象模版(AbstractClass)角色有如下的责任:

定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤。

定义并实现了一个模版方法。这个模版方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。

具体模版(ConcreteClass)角色有如下的责任:

实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤。

每一个抽象模版角色都可以有任意多个具体模版角色与之对应,而每一个具体模版角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。

三、 模板方法模式的示意性代码

// Template Method pattern -- Structural example

using System;

// "AbstractClass"

abstract class AbstractClass

{

// Methods

abstract public void PrimitiveOperation1();

abstract public void PrimitiveOperation2();

// The Template method

public void TemplateMethod()

{

Console.WriteLine("In AbstractClass.TemplateMethod()");

PrimitiveOperation1();

PrimitiveOperation2();

}

}

// "ConcreteClass"

class ConcreteClass : AbstractClass

{

// Methods

public override void PrimitiveOperation1()

{

Console.WriteLine("Called ConcreteClass.PrimitiveOperation1()");

}

public override void PrimitiveOperation2()

{

Console.WriteLine("Called ConcreteClass.PrimitiveOperation2()");

}

}

/// <summary>

/// Client test

/// </summary>

public class Client

{

public static void Main( string[] args )

{

// Create instance and call template method

ConcreteClass c = new ConcreteClass();

c.TemplateMethod();

}

}

四、 继承作为复用的工具

使用继承作为复用的手段必须慎重,C#语言的设计师对使用继承作为复用的工具有着不同层次上的认识。

不知其一

首先,初学C#的程序员可能不知道什么是继承,或者认为"继承"是高深的工具。那时候,大部分的功能复用都是通过委派进行的。

知其一、不知其二

然后慢慢地,他们发现在C#语言里实现继承并不困难,并且初步认识到继承可以使子类一下子得到基类的行为。这时他们就会跃跃欲试了,试图使用继承作为功能复用的主要工具,并把原来应当使用委派的地方,改为使用继承,这时继承就有被滥用的危险。

知其二

很多面向对象的设计专家从19xx年就开始警告继承关系被滥用的可能。有一些面向对象的编程语言,如SELF语言,甚至将类的继承关系从语言的功能中取消掉,改为完全使用委派。

其他的设计师虽然不提倡彻底取消继承,但无一例外地鼓励在设计中尽可能使甩委派关系代替继承关系。比如在【GOF95】一书中,状态模式、策略模式、装饰模式、桥梁模式以及抽象工厂模式均是将依赖于继承的实现转换为基于对象的组合和聚合的实现,这些模式的要点就是使用委派关系代替继承关系。

知其三

是不是继承就根本不该使用呢?事实上对数据的抽象化、继承、封装和多态性并称C#和其他绝大多数的面向对象语言的几项最重要的特性。继承不应当被滥用,并不意味着继承根本就不该使用。因为继承容易被滥用就彻底抛弃继承,无异于因噎废食。

继承使得类型的等级结构易于理解、维护和扩展,而类型的等级结构非常适合于抽象化的设计、实现和复用。尽管【GOF95】所给出的设计模式基本上没有太多基于继承的模式,很多模式都是用继承的办法定义、实现接口的。多数的设计模式都描写一个以抽象类作为基类,以具体类作为实现的等级结构,比如适配器模式、合成模式、桥梁模式、状态模式等。

模版方法模式则更进了一步:此模式鼓励恰当地使用继承。此模式可以用来改写一些拥有相同功能的相关的类,将可复用的一般性的行为代码移到基类里面,而把特殊化的行为代码移到子类里面。

因此,熟悉模版方法模式便成为一个重新学习继承的好地方。

五、 一个实际应用模板方法的例子

下面的例子演示了数据库访问的模板方法。实际应用时,请确保C盘根目录下有nwind.mdb这个Access数据库(可以从Office的安装目录下找到。中文版用户的请注意字段名可能有所不同)。

// Template Method pattern -- Real World example

using System;

using System.Data;

using System.Data.OleDb;

// "AbstractClass"

abstract class DataObject

{

// Methods

abstract public void Connect();

abstract public void Select();

abstract public void Process();

abstract public void Disconnect();

// The "Template Method"

public void Run()

{

Connect();

Select();

Process();

Disconnect();

}

}

// "ConcreteClass"

class CustomerDataObject : DataObject

{

private string connectionString =

"provider=Microsoft.JET.OLEDB.4.0; "

+ "data source=c:\\nwind.mdb";

private string commandString;

private DataSet dataSet;

// Methods

public override void Connect( )

{

// Nothing to do

}

public override void Select( )

{

commandString = "select CompanyName from Customers";

OleDbDataAdapter dataAdapter = new OleDbDataAdapter(

commandString, connectionString );

dataSet = new DataSet();

dataAdapter.Fill( dataSet, "Customers" );

}

public override void Process()

{

DataTable dataTable = dataSet.Tables["Customers"];

foreach( DataRow dataRow in dataTable.Rows )

Console.WriteLine( dataRow[ "CompanyName" ] );

}

public override void Disconnect()

{

// Nothing to do

}

}

/// <summary>

/// TemplateMethodApp test

/// </summary>

public class TemplateMethodApp

{

public static void Main( string[] args )

{

CustomerDataObject c = new CustomerDataObject( );

c.Run();

}

}

六、 模版方法模式中的方法

模版方法中的方法可以分为两大类:模版方法(Template Method)和基本方法(Primitive Method)。

模版方法

一个模版方法是定义在抽象类中的,把基本操作方法组合在一起形成一个总算法或一个总行为的方法。这个模版方法一般会在抽象类中定义,并由子类不加以修改地完全继承下来。

基本方法

基本方法又可以分为三种:抽象方法(Abstract Method)、具体方法(Concrete Method)和钩子方法(Hook Method)。

抽象方法:一个抽象方法由抽象类声明,由具体子类实现。在C#语言里一个抽象方法以

abstract关键字标示出来。

具体方法:一个具体方法由抽象类声明并实现,而子类并不实现或置换。在C#语言里面,一个具体方法没有abstract关键字。

钩子方法:一个钩子方法由抽象类声明并实现,而子类会加以扩展。通常抽象类给出的实现是一个空实现,作为方法的默认实现。(Visual FoxPro中项目向导建立的项目会使用一个

AppHook类实现监视项目成员变化,调整系统结构的工作。)钩子方法的名字通常以do开始。

七、 重构的原则

在对一个继承的等级结构做重构时,一个应当遵从的原则便是将行为尽量移动到结构的高端,而将状态尽量移动到结构的低端。

19xx年,Auer曾在文献【AUER95】中指出:

应当根据行为而不是状态定义一个类。也就是说,一个类的实现首先建立在行为的基础之上,而不是建立在状态的基础之上。

在实现行为时,是用抽象状态而不是用具体状态。如果一个行为涉及到对象的状态时,使用间接的引用而不是直接的引用。换言之,应当使用取值方法而不是直接引用属性。

给操作划分层次。一个类的行为应当放到一个小组核心方法(Kernel Methods)里面,这些方法可以很方便地在子类中加以置换。

将状态属性的确认推迟到子类中。不要在抽象类中过早地声明属性变量,应将它们尽量地推迟到子类中去声明。在抽象超类中,如果需要状态属性的话,可以调用抽象的取值方法,而将抽象的取值方法的实现放到具体子类中。

如果能够遵从这样的原则,那么就可以在等级结构中将接口与实现分隔开来,将抽象与具体分割开来,从而保证代码可以最大限度地被复用。这个过程实际上是将设计师引导到模版方法模式上去。

相关推荐