持之以恒
分类: 项目管理
2009-08-05 18:06:13
对手头的问题具有针对性以及对将来的问题和需求要有足够的通用性。
软件的可复用性
为了实现良好的设计我们必须复用以前使用过的成功的解决方案。
将面向对象软件的设计经验以人们能够有效利用的形式——设计模式记录下来。每一个设计模式系统的命名、解释和评价了面向对象系统中的一个重要的重复出现的设计。
设计模式使人们能够更为简单方便的复用成功的设计和体系结构。
设计模式帮助你做出有利于系统复用的选择,避免设计损害系统的复用性。
提高现有系统的文档管理和系统维护的有效性。
目的:帮助设计者能够更好的更快的完成系统的设计。
每一个模式描述了一个在我们周围不断重复发生的问题以及该问题解决方案的核心。
模式的核心在于:提供了相关问题的解决方案
模式的名称:一个助记名,它用一两个词来描述模式的问题、解决方案和效果。
问题:描述了应该在何时使用模式。它解释了设计问题和问题存在的前因后果。
n 描述了特定的设计问题 如何使用对象表示算法
n 描述了导致不灵活设计的类和对象结构
n 使用模式必须满足的一系列的先决条件
解决方案:描述了设计的组成成分,他们之间的相互关系以及各自的职责和协作方式。
解决方案并不描述一个特定而具体的设计或者实现,而是提供设计问题的抽象的描述和怎样使用一般意义的元素组合来解决这个问题。
效果:描述了模式的应用效果和使用模式应该权衡的问题
对于评价设计选择和理解使用模式的代价及好处具有重要的意义。
效果:系统的灵活性、扩充性、可移植性、可复用性
用来在特定场景下解决一般设计问题的类和相互通信的对象的描述。
一个设计模式命名、抽象和确定了一个通用设计结构的主要方面,这些设计结构能够被用来构建可复用的面向对象的设计
设计模式确定了所包含的类和实例,他们的角色、协作方式以及职责分配。
每一个设计模式都集中于一个特定的面向对象的设计问题或设计要点,描述了什么时候使用它,在另一些设计约束条件下是否还能够使用,以及使用的效果和如何取舍的问题。
模型—视图—控制器
三类对象,模型表示的是应用对象,视图View是在屏幕上的表示,控制器Controller定义用户界面对用户输入的响应方式。
MVC将三种对象进行分离以提高系统的灵活性和复用性
MVC中的主要的模式Observer模式Composite模式和Strategy模式
Observer模式:视图和模型进行分离的设计(使得一个对象的改变能够影响到另一些对象,而这个对象并不需要知道那些被影响对象的细节)
Composite模式:实现视图的嵌套,允许创建一个类的层次结构,一些子类定义了原子对象、而其他的类定义了组合对象。这些组合对象是原子对象组合而成的更为复杂的对象。
Strategy模式:View-Controller关系是Strategy模式的一个例子。View使用Controller的子类实现一个特定的相应策略。要实现不同的相应策略,只要使用不同种类的Controller实例进行替换即可。一个策略是一个表述算法的对象。当你想静态的或者是动态的替换一个算法的时候,或者你有很多的实现的算法的时候,或者算法封装了复杂的数据结构的时候,使用策略模式十分有用。
MVC中还是使用了其他的设计模式:比如Factory模式(指定视图的缺省的控制器)、Decorator模式(增加视图滚动)
模式的名称简洁的描述了模式的本质
设计模式是用来做什么的
它的基本原理和意图是什么
它解决什么样的特定的设计问题
用以说明一个设计问题以及如何使用模式中的类、对象来解决该问题的特定的情景。该情景会帮助随后对模式更抽象的描述
什么情况下可以使用该设计模式
该模式可以改进那些不良设计
你怎样识别这些情况
采用基于对象建模技术的表示法对模式中的类进行图形描述。
设计模式中的类或者是对象以及他们各自的职责
模式的参与者怎样的协作以实现他们的职责
模式怎样支持他的目标
使用模式的效果和它所作的权衡取舍?系统结构中的哪部分可以独立改变
与这个模式紧密相连的模式有哪些
其间的重要不同是什么
这个模式应该和哪些模式一起使用
创建型模式:与对象的创建有关
结构型模式:处理类或者是对象的组合
行为型模式:对类或者对象怎样交互和相互分配职责进行描述
类模式处理的是类和子类之间的关系,这些关系通过继承进行建立,是静态的,在编译的时刻便确定了下来
对象模式处理的是对象之间的关系,这些关系在运行的时刻是可以发生变化的,是动态的。
创建型的类模式:将对象的部分的创建工作延迟到子类。
创建型的对象模式:将对象的部分的创建工作延迟到另一个对象中
结构型的类模式使用继承机制来组合类
结构型的对象模式:描述了对象的组装方式
行为型类模式使用继承来描述算法和控制流
行为型的对象模式:描述了一组对象怎样协作完成单个对象无法完成的任务。
面向对象系统设计中的最困难的部分是:将系统分解成对象的集合
需要进行考虑的因素:
封装、粒度、依赖关系、灵活性、性能、演化、复用等。他们都会影响系统的分解,并且这些因素常常是相互冲突的。
可能的解决的方法
l 写出一个问题的描述,挑出其中的名词和动词,进而创建相应的类和操作
l 关注与系统的协调和职责关系
l 对现实得世界进行建模,将分析发现的对象转化到设计中。
注意
严格的反映现实世界的模型,并不能产生反映将来世界的系统。
设计中的抽象对于产生灵活的设计至关重要。
设计模式的作用:
帮你确定并不明显的抽象和描述这些抽象的对象。
对象在大小、数目上变化很大。
有以下的几个概念:型构、接口、类型、动态绑定、多态。
l 对象声明的每一个操作指定的操作名、作为参数的对象和返回值,这就是所谓的操作的型构。
l 对象操作所定义的所有的操作型构的集合被称为对象的接口。
l 对象的接口描述了该对象所能接受的全部请求的集合,任何匹配对象接口中型构的请求都可以发送给该对象。
l 类型:用来标示特定的接口的一个名字。
l 如果一个对象接受了”X”接口所定义的全部的操作请求,那么我们就说该对象具有”X”类型
l 一个对象可以具有许多的类型,不同的对象可以共享一个类型。
l 对象接口中的某部分可以使用某个类型进行刻画,而其他部分可以使用其他接口进行刻画
l 两个类型相同的对象只需共享他们的部分的接口。
l 接口可以包含其他的接口作为子集
l 当一个类型的接口包含另一个类型的接口的时候,我们就说它是另一个类型的子类型。另一个类型称之为超类型。也就是说:子类型继承了超类型的接口
l 当给对象发送请求的时候,所引起的具体的操作既与请求本身有关,又与接受的对象有关。支持相同请求的不同的对象可能对请求所激发的操作有不同的实现。
l 发送给对象的请求和它的相应的操作在运行时刻的连接就称之为动态绑定。
l 动态绑定允许你在运行时刻彼此替换相同接口的对象。可替换性==>多态
一些重要的概念:
实例化、继承、虚函数、纯虚函数、抽象类、混入类、重载、重写、多态的实现的必要条件
类(class)继承和接口继承(子类型化)的比较:
l 一个对象的类定义了对象是怎么实现的,同样定义了对象的内部状态和操作的实现。
l 对象的类型(Type)只和他的接口有关,接口即对象能响应请求的集合。
l 一个对象可以有多个类型,不同类的对象可以有相同的类型。
l 类继承根据一个对象的实现定义另一个对象的实现。它是代码和表示的共享机制
l 接口继承(子类型化):描述了一个对象在什么时候被用来替换另一个对象
类继承:通过复用父类的功能而扩展应用功能的基本机制。
继承的另一个功能:继承所拥有的定义具有相同接口的对象族的能力(通过抽象类进行继承)
面向对象系统中功能复用最两种常见的技术是对象组合和类继承。
l 类继承允许你用其他类实现一个类的实现
l 这种通过生成子类的方式进行的复用通常被成为”白箱复用”。在继承的方式中父类的内部细节对子类可见。
l 对象组合要求被组合的对象具有良好定义的接口。这种复用方式称为黑箱复用。因为对象的内部细节是不可见的。
类继承的特点:
l 比较简单、方便。函数的重写。(优点)
l 类继承是在编译时刻进行确定的,无法在运行的时刻改变从父类继承的实现。
l 类继承破坏了封装性,继承对子类揭示了其父类的实现细节。
l 子类的实现和父类中有紧密依赖的关系,以至于父类中实现中任何的变化都将导致子类中的变化。
对象的组合:通过获得其他对象的引用,而在运行时刻动态定义的。
l 对象只能通过接口进行访问,从而没有破坏其封装性。
l 只要类型一致,运行的时刻可以使用一个对象代替另一个对象。
l 因为对象是基于接口写的,所以实现上存在较少的依赖关系。
l 优先使用组合有助于每个类被封装,并集中在单个任务上。
l 类和类的继承层次会保持较小的规模,并不可能成为不可控制的庞然大物。
l 基于对象组合的设计会有更多的对象(而有较少的类),且系统的运行将依赖于对象之间的关系,而不是被定义在某个类中。
优先使用对象组合,而不是类继承
委托是一种组合方法,有两个对象处理一个请求,接受请求的对象将操作委托给他的代理者。
另外的一种复用技术是参数化类型技术,也称为类属(或者叫做模板)
继承、组合、参数化类型的比较
l
组合技术允许你在组合时刻改变被组合的行为。但是存在间接性、比较低效
l
继承允许你提供操作的缺省实现,并通过子类重定义这些操作。
l
参数化类型允许你改变类所用到的类型。
下面阐述一些导致重新设计的一般的原因,以及解决这些问题的设计模式
l 通过显示的指定一个类来创建对象è在创建对象的时候指定类名将使你受特定实现的约束,而不是特定的接口的约束。这使得未来的变化变得更加的复杂。要避免这些情况,应该间接地创建对象。
设计模式:Abstract Factory模式、 Factory模式Prototype模式
l 对特殊操作的依赖,当你为请求指定一个特殊的操作的时候,完成该请求的方式就固定了下来。为了避免将请求的代码写死,你将可以在编译时刻,或者在运行时刻很方便的改变相应请求的方式。
设计模式:Chain of Resposibility模式Command模式
l 对硬件和软件平台的依赖:外部操作系统的接口和应用编程接口,在不同的软硬件的平台上是不同的,依赖于特定平台的软件将很难移植到其他的平台上。甚至都很难跟上本地平台的更新。所以设计系统时限制其平台相关性就很重要了。
设计模式:Abstract Factory模式Bridge模式
l 对对象的表示或者是实现的依赖:知道对象怎样表示、保存、定位、或者实现的客户在对象发生变化时可能也需要变化。对客户隐藏这些信息能阻止连锁变化.
设计模式:Abstract Factory模式 Bridge模式 Memento模式Proxy模式
l 算法依赖:算法在开发或者是复用的时候常常被扩展,优化和代替。依赖于某个特定算法的对象在算法发生变化的时候不得不进行变化。因此有可能发生变化的算法应该被”孤立”起来。(算法的对象化)
设计模式:Builder模式、Iterator模式Strategy模式,Template模式Visitor模式
l 紧耦合:紧耦合的类很难独立的被复用,因为他们是相互依赖的。难以进行移植复用,松散耦合:提高了一个类被复用的可能性。设计模式使用抽象耦合和分层技术(TCP/IP)来系统的松散的耦合性.
设计模式:Abstract Factory模式Command模式、Façade模式、Mediator模式、Observer模式、Chain of Responsibility模式
l 通过子类进行功能上的扩充:很难通过子类来定制对象。每一个子类都有固定的开销(Init、Destory)定义子类要对父类有深入的了解,子类的方法可能会导致类的爆炸,因为即使是一个简单的扩充,你将不得不引入许多新的子类
继承之外的组合对象行为的另一种灵活的方法:一般对象的组合技术和具体的委托的技术。
新的功能可以通过以新的方式组合已有的对象,而不是通过定义已存在类的子类的方式加到应用中去。但是过多的使用组合会使程序的结构变得难于理解。
在许多设计模式产生的设计中,你可以定义一个子类,并将它的实例和已经存在的实例进行组合引入定制的功能。
设计模式:Bridge模式、Chain of Responsibility模式、Composite模式、Decorator模式、Observer模式、Strategy模式
l 不能方便的对类进行修改:有时你不得不改变一个难以修改的类。也许你需要修改源代码,而你有没有,或者可能对类的任何的改变,都会要求改变许多已经存在的其他的子类。
设计模式:Adapter模式Decorator模式Visitor模式
l 应用程序
优先进行考虑:它内部的复用性、可维护性、可扩充性。
内部的复用性保证你不做多余的设计和实现,设计模式通过减少依赖性,来提高内部的复用性。
松散的耦合性也增强一类对象与其他多个对象协作的可能性。
l 工具箱(API)(Toolkit)
比如说:C++中的I/o流库。工具箱并不强制应用采用某个特定的设计,他们只是为应用提供功能上的帮助。工具箱强调的是代码的复用,他们是面向对象环境下的子程序库。
工具箱的设计要避免假设和依赖。因为工具箱的设计者不知道什么应用使用该工具箱,以及对工具箱有什么特定的需求。
l 框架
n 一类特定的软件可复用设计的一组相互协作的类
n 可以定义框架抽象类的应用的相关的子类,从而将一个框架定制为特定的应用。
n 框架规定了应用的体系结构:它定义了整体结构,类和对象的分割,各部分的主要的责任、类和对象怎样的协作,以及对应的控制流程。框架定义了这些设计参数,以便应用设计者,或者应用实现者,能够集中精力于应用本身的实现细节。(想一想MFC对应的框架结构)
n 框架记录了其应用领域共同的设计决策。所以框架更加强调的是:设计复用,尽管框架本身包含立即可用的子类。
n 这个层次的复用导致了应用和它所基于的软件之间的反向控制(inversion of control)
u 当你使用工具箱的时候,或者是传统的子程序的时候,你需要写的是应用程序的主体和你所想复用的代码。
u 当你使用的是框架结构的时候,你应该复用应用的主体,写主体调用的代码。你不得不以特定的名称和调用的方式,来写相应操作的实现。但是这会减少你所做的相应的设计上的决策。
n 框架的设计者必须决定一个要适应于该领域的所有的应用的体系结构。框架对于应用而言,最重要的在与他的体系结构。所以设计的框架必须尽可能的灵活、可扩充。
n 设计模式的问题对于框架的设计最具重要性。一个使用设计模式的框架比不用设计模式的框架更有可能获得高层次的设计复用和代码复用。
n 设计模式和框架的区别
u 设计模式比框架更加的抽象
u 设计模式是比框架更小的体系结构元素
u 框架比设计模式更加特例化
n 框架变得越普遍和重要,他们是面向对象系统获得最大的复用的方式。较大的面向对象应用将会由多层彼此合作的框架组成。
目的 |
设计模式 |
可变的方面 |
创建 |
Factory模式 |
被实例化的子类 |
Abstract Factory模式 |
产品对象家族 |
|
Builder模式 |
如何创建一个组合对象 |
|
Prototype模式 |
被实例化的类 |
|
Singleton模式 |
一个类的唯一实例 |
|
结构 |
Façade模式 |
一个子系统的接口 |
Adapter模式 |
对象的接口 |
|
Bridge模式 |
对象的实现 |
|
Composite模式 |
一个对象的结构和组成 |
|
Decorator模式 |
对象的职责,不产生子类 |
|
Flyweight模式 |
对象的存储开销 |
|
Proxy模式 |
如何访问一个对象;该对象的位置 |
|
行为 |
Chain of Responsibility模式 |
满足一个对象的请求 |
Command模式 |
何时怎样满足一个请求 |
|
Interpreter模式 |
一个语言的文法及解释 |
|
Iterator模式 |
怎样遍历、访问一个聚合中的元素 |
|
Mediator模式 |
对象间是怎么交互的、和谁交互 |
|
Memento模式 |
一个对象的哪些私有信息应该放在该对象之外,以及在什么时候进行存储。 |
|
Observer模式 |
多个对象依赖于另外一个对象,而这些对象又如何保持一致 |
|
State模式 |
对象的状态 |
|
Strategy模式 |
算法 |
|
Template模式 |
算法中的某些步骤 |
|
Visitor |
某些可以作用于一组对象上的操作,但是不修改这些对象的类 |