类和类型的区别,类定义了对象内部状态和操作的实现,类型则是和接口的概念对应的。
创建型模式强制你采用针对接口的编程习惯,而不是针对实现的编程。
继承和组合的比较,继承多是静态代码复用,子类了解父类的实现,某种意义上破坏了封装。组合是更好的封装,更依赖于接口的定义,更依赖于运行时对象之间的关系来实现程序的逻辑。
用设计模式应付未来的变化
用创建模式产生对象实例而不指定类名。
用Command或者Chain of Responsibility避免把请求操作的代码写死。
利用abstract factory和Bridge分离设计和实现以应付平台和API的变化。
利用Adapter,Decorator和Visitor改变已有对象的行为。
类厂
类厂语法特点是产生实例的时候并没有指定要产生的实例的类名。 程序会维护一个全局的基类类厂指针,使得可以在运行时替换类厂实例。
类厂分类的方法可能是按风格,可能是按平台。程序的逻辑决定什么时候信息足够,可以实例化什么类厂。类厂的类型可以是编译期决定的,比如跨平台的应用,类厂实现必须是按平台分的。也可以是运行期才有足够的信息决定类厂的类型,比如用户对程序的风格设置。
更高级的方法,把类厂和一个字符串(类厂的名字)对应起来,客户程序传入一个字符串,程序逻辑返回一个类厂实例。
一旦类厂的实例确定了,程序的一个方面就确定了,也就是一般来说使用一个类厂,必须使用全部的这个类厂产生的实例。
Window System
Window类是系统定义的抽象的window系统,决定了系统定义的可以做事情。Window类把实际的操作委托给WindowImp的继承类。WindowSystemFactory是产生WindowImp继承类的实例的类厂接口,不同的类厂实现对应不同的Imp类例如WindowImp,FontImp。
Imp类例如WindowImp,FontImp像是给抽象系统Window提供的API,这API隐藏了实际OS相关的实现,一旦系统决定了类厂的实例,API就定了。
Operation和request的封装
对一个系统来说,request来自各个方面,例如OS,鼠标,键盘,网络,一但request产生,用户希望某个operation被运行。但是operation的实现可能分布在代码的各个地方,各种不同的类。
最直接的办法是把operation的代码封装在request的来源里,例如MenuItemChangeColor::Click(){}。但是这种方法的使得代码结合的太紧密。
识别request的来源的实质是需要参数化request的来源,比如MenuItemChangeColor,设计模式里用一个object来参数化,这个object是command。
command有一个方法Execute,里面封装了operation的代码,也可以在这些代码里把operation委托给程序的其他的办法。
access 和traversal mechanisms的封装
Iterator Pattern封装了这些机制,使用Iterator,客户程序不需要知道需要遍历的结构的内部细节,而且遍历的状态被保存在iterator里,所以可以同时有多个遍历同时运行。而且可以有不同类型的Iterator实现,比如如果结构是一个tree,可以PreIterator, PostIterator,MidIterator几个继承类。
遍历的算法经常需要积累信息,比如遍历一段文本,计数word,不同的算法可能需要积累不同的信息,不好的做法是把积累信息的code集成到Iterator里,这样会造成紧密结合,所以最好能把遍历里的action和Iterator分开。
引入Visitor
一般的遍历的所做的事情,例如分析问题的代码如下,把action封装在类SpellingChecker里,这个类的一个方法接受被遍历的对象的指针。 上面code不好的地方是一堆if,而且随着系统的进化,这个方法会不停的被改变。更好一点的实现方法是
上面的机制抽象出来就得到了Visitor模式,首先遍历时候的action不一定是check,我们称抽象出来的封装action的类为Visitor。同样的,被访问的对象的抽象方法(CheckMe)称为Accept(Visitor&)。不同的遍历action被封装在Visitor的不同的method里。
No comments:
Post a Comment