设计模式 之 引言

1. 设计模式定义

模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心思想,这样就能直接利用此方案,不必做重复劳动;

GOF中的设计模式是对用来在特定场景下解决一般设计问题的类和相互通信的对象的描述;

2. 设计模式分类

GOF中共包含了23种设计模式,根据其目的可以将模式分为创建型、结构型和行为型三种;

(1) 创建型:

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

包含抽象工厂、生成器、工厂方法(类)、原型、单件等5种模式;

(2) 结构型:

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

包含适配器(类)、桥接、组合、装饰、外观、享元、代理等7种模式;

(3) 行为型:

行为型模式对类或者对象怎样交互和怎样分配职责进行描述;行为型类模式使用继承描述算法和控制流,而行为型对象模式则描述了一组对象怎样协作完成单个对象所无法完成的任务。

包含职责链、命令、解释器(类)、迭代器、中介者、备忘录、观察者、状态、策略、模板方法(类)、访问者等11中模式;

3. 设计模式解决问题的方法

(1) 寻找合适的对象

面向对象设计最困难的部分是将系统分解成对象集合;分解过程包含很多因素,并且它们通常还是互相冲突的;

设计的许多对象来源于现实世界的分析模型,但是,设计结果所得到的类通常在现实世界中并不存在,有些是像数组之类的低层类,而另一些则层次较高;

设计模式帮助确定并不明显的抽象和描述这些抽象的对象;这些对象在分析阶段、甚至设计阶段早期并不存在,后来为使设计更灵活、复用性更好才将它们发掘处来;

(2) 决定对象的粒度

对象在大小和数目上变化极大,它们能表示下至硬件或上至整个引用的任何事物,设计模式很好的讲述了如何决定对象的粒度问题;

(3) 指定对象接口

设计模式通过确定接口的主要组成成分及经接口发送的数据类型来帮助定义接口;设计模式还会帮助告诉接口中不应该包括哪些东西;

设计模式也指定了接口之间的关系;特别是,它们进程要求一些类具有相似的接口,或者它们对一些类的接口做了限制;

(4) 描述对象的实现

针对接口编程,而不是针对实现编程;不将变量声明为某个特定的具体类的实利对象,而是让它遵从抽象类所定义的接口;当不得不在系统的某个地方实例化具体类时,可以使用创建型模式,这些模式提供不同的方式以在实例化时建立接口和实现的透明连接;

(5) 运用复用机制

复用的三种方法:继承、组合、参数化类型(如C++模板);继承允许提供操作的默认实现,并通过子类重定义这些操作;对象组合技术允许在运行时改变被组合的行为,但是它存在间接性,比较低效;参数化类型允许改变类用到的类型;但是继承和参数化类型都不能在运行时改变;

优先使用对象组合,而不是继承;

委托是一种组合方法,它使组合具有与继承同样的复用能力,在委托方式下,有两个对象参与处理一个请求,接受请求的对象将操作委托给它的代理者,这类似于子类将请求交给它的父类处理;

参数化类型允许在定义一个类型时不用指定该类型用到的其他所有类型,未经指定的类型在使用时以参数形式提供;

(6) 关联运行时和编译时的结构

面向对象程序运行时的结构通常与它的代码结构相差较大;代码结构在编译时就确定下来了,它由继承关系固定的类组成;而程序的运行时结构是由快速变化的通信对象网格组成;两个结构彼此独立;系统运行时的结构更多的受到设计者而不是编程语言的影响;

以聚合和相识为例,聚合意味着一个对象拥有另一个对象或对另一个对象负责;聚合意味着聚合对象和其所有者具有相同的生命周期;相识意味着一个对象仅仅知道另一个对象,相识也被称为关联或引用;相识的对象可能请求彼此的操作,但是它们不为对方负责;相识是比聚合要弱的关系,它标识了对象之间较松散的耦合关系;C++中,聚合可以通过定义表示真正实例的成员变量来实现,但是更通常的做法是将这些成员变量定义为实例指针或引用;相识也是以指针或引用来实现的;从根本上讲,是聚合还是相识是由设计意图而不是显示的语言机制决定的;

(7) 设计应支持变化

设计模式可以确保系统以特定的方式变化,从而帮助你避免重新设计系统,每个设计模式允许系统结构的某个方面的变化独立于其他方面;

以下为一些导致重新设计的原因:

a) 通过显式的指定一个类来创建对象

创建对象时指定类名将受到特定实现的约束而不是特定接口的约束,这会使未来的变化更复杂,要避免这种情况,应该间接的创建对象;

设计模式:抽象工厂、工厂方法、原型

b) 对特殊操作的依赖

当为请求指定一个特殊操作时,完成该请求的方式就固定下来了,为了避免将请求代码写死,可以在编译时或运行时方便的改变响应请求的方法;

设计模式:职责链、命令

c) 对硬件和软件平台的依赖

外部的操作系统接口和引用编程接口在不同的软硬件平台上时不同的。依赖于特定平台的软件将很难移植到其他平台上,甚至很难跟上本地平台的更新,所以设计系统时限制平台相关性就很重要了;

设计模式:抽象工厂、桥接

d) 对对象表示或实现的依赖

知道对象怎样表示、保存、定位或实现的客户在对象发生变化时可能也需要变化;对客户隐藏这些信息能够阻止连锁变化;

设计模式:抽象工厂、桥接、备忘录、代理

e) 算法依赖

算法在开发和复用时常常被扩展、优化和替代;依赖于某i个特定算法对象在算法发生变化时不得不变化;因此由可能发生变化的算法应该被孤立起来;

设计模式:生成器、迭代器、策略、模板方法、访问者

f) 紧耦合

紧耦合的类很难独立的被复用,因为它们时互相依赖的。紧耦合产生单块额系统,要改变或者删掉一个类,你必须理解和改变其他许多类;这样的系统是一个很难学习、移植和维护的密集体;

松散耦合提高了一个类本身被复用的可能性,并且系统更易于学习、移植、修改和扩展。设计模式使用抽象耦合和分层技术来提高系统的松散耦合性。

设计模式:抽象工厂、命令、外观、中间者、观察者、职责链

g) 通过生成子类来扩充功能

通常很难通过定义子类来定制对象;每一个新类都有固定的开销;定义子类还需要对父类有深入的了解;例如,重定义一个操作可能需要重定义其他操作。一个被重定义的操作可能需要调用继承下来的操作,且子类方法会导致类爆炸,因为即使对于一个简单的扩充,你也不得不引入许多新的子类;

一般的独享组合技术和具体的委托技术,时继承之外组合对象行为的另一个灵活的方法;新的功能可以通过以新的方式组合已有对象,而不是通过定义已经存在的类的子类的方式加到引用中去;另一方面,过多的使用对象组合会使设计难于理解;许多设计模式产生的设计中,可以顶一个子类,且将它的实例和已经存在的实例进行组合来引入定制的功能;

设计模式:桥接、职责链、组合、装饰、观察者、策略

h) 不能方便的对类进行修改

有时不得不改变一个难以修改的类,也许需要代码而又没有,或者可能对类的任何改变多会要求修改许多已经存在的其他子类;设计模式提供在这些情况下对类进行修改的方法;

设计模式:适配器、装饰、访问者

 

posted @ 2020-04-07 21:50  AlexAlex  阅读(368)  评论(0编辑  收藏  举报