1、现代软件设计技术,潘爱民http:/ Programming补充一些patterns构造框架(framework)的技术构造可重用类库的技术,复习:creational patters,Factory Method本质:用一个virtual method完成创建过程Abstract Factory一个product族的factory method构成了一个factory接口Prototype通过product原型来构造product,Clone+prototype managerBuilder通过一个构造算法和builder接口把构造过程与客户隔离开Singleton单实例类型,如何构造这单个
2、实例?如何访问这单个实例?Finder把对象的获取过程与客户隔离开,复习:Structural patterns,Adapter 、bridge、facadeadapter用于两个不兼容接口之间的转接bridge用于将一个抽象与多个可能的实现连接起来facade用于为复杂的子系统定义一个新的简单易用的接口composite、decorator和proxycomposite用于构造对象组合结构decorator用于为对象增加新的职责proxy为目标对象提供一个替代者flyweight针对细粒度对象的一种全局控制手段,复习:Behavioral Patterns,Command 用对象封装命令,使
3、得命令可以被传递、记录、排队等Iterator 把对聚合体对象的访问封装起来Observer 建立起一对多的通信模型,特别适合于更新通知和事件模型Strategy 把一个对象或者类的某些行为封装到另一个单独的对象中Visitor把对一个结构模型的操作单独组织到一个类中,复习:Behavioral Patterns(续一),Chain of Responsibility 请求的处理过程,沿着链传递,decouple发送方和接收方Interpreter 在类层次结构中,在特定环境的“interpret”过程Mediator 用一个mediator来decouple各同等单元Memento 在对象之
4、外保存对象的内部状态State 把一个对象的状态独立出来,动态可变换状态对象的类型Template Method 在基类中定义算法的骨架,把某些细节延迟到子类中,复习:Behavioral Patterns(续二),Strategy、Iterator、Mediator、State、command用一个对象来封装某些特性,比如变化、交互、状态、行为、命令Mediator、ObserverObserver建立起subject和observer之间的松耦合连接mediator把约束限制集中起来 -中心控制command、Chain of Responsibility、interpretercomma
5、nd模式侧重于命令的总体管理Chain of Responsibility侧重于命令被正确处理interpreter用于复合结构中操作的执行过程,Generic programming,思想:“通过参数化技术达到重用的目的(reuse through parameterization)”,使得组件更容易被定制。实现静态配置代码,从而获得很高的效率。 Generic Programming可以消除类型和算法之间本来不必要的相依性STL是成功的generic programming典型generic programming限制代码产生的方式:用实体类型代替类型参数,使这些预先编制好的代码模型成为真
6、正的代码,无法产生完全新的代码。,相关的programming,Aspect-Oriented Programming (AOP) An aspect is a modular unit that cross-cuts the structure of other modular units Aspects exist in both design and implementation. A design aspect is a modular unit of the design that cross-cuts the structure of other parts of the desi
7、gn. A program or code aspect is a modular unit of the program that cross-cuts other modular units of the program. 把问题分解为功能单元(组件)和aspect在AOP系统中,组件和aspects(交织)组合起来得到一个系统的具体实现。交织组合既可以在compile-time,也可以在runtimeAOSD, 参考:http:/ programming,Generative Programming 建立起一族软件系统的模型,在特定的要求下,利用一些基本的、可重用的组件,通过配置,能够自
8、动根据需要产生一个高度定制和优化的软件系统实例一些原则用参数化技术来概括出差异性对于相依性和交互进行分析和建模通过静态链接(compile-time)消除不必要的开销,以及执行与特定领域相关的优化将问题空间和方案空间分离,通过配置建立两者的映射关系Separation of concerns: borrowed from AOP特点Generative Programming涉及到软件开发过程的各个阶段与Domain Engineering结合A Model-Based Approach:http:/www.sei.cmu.edu/domain-engineering/domain_engin
9、eering.htmlActive Libraries,C+ Generic Programming,Template技术使C+成为two-level languagemetaprogram从科学计算用途-一般性的抽象,即generic programming对于编译器代码产生、优化在编译时刻,实现静态绑定 partial evaluation对于库开发人员Active libraries,提供一种抽象的功能,并且控制优化过程许多技术,如policy(traits)、编译时刻计算功能对于应用开发人员定制template class或者template function,C+ Generic P
10、rogramming(续),设计思想编译时刻程序设计,类似于logic-programming即,在compile-time让编译器完成一些功能,例如静态的计算功能if/else,loop,switch对type进行一些基本的逻辑操作(编程)保证类型安全宁可要compile-time error,也不要runtime error尽可能地泛化 抽象性跟传统的设计方法结合起来,比如利用patterns,Template基础 class template,templateclass Array public:T,使用:Array a1;Array a2;,Template基础 模板特化templat
11、e specialization,templateclass Array public:char,Template基础 部分模板特化 partial template specialization,templateclass Array public:T*Visual C+ 6不支持部分模板特化,Template基础 函数模板function template,template void Swap(T ,模板参数,compile-time起作用,函数参数,runtime起作用,Template基础 函数对象泛化generalized functors(function objects),fun
12、ctor:重载了operator()的C+对象,扩展了函数指针的概念,可以增加内部状态,可以被当作对象来传递,具有值语义(value semantic)。它可以是template class,也可以不是template class Functorpublic :ResultType operator()();/ other member functionprivate :/ implementation;用法:Functor MyFunctor(val1);int Result = MyFunctor();,Template技术 代替runtime的if/else,/ Class declar
13、ationstemplateclass ConditionProcess ;class ConditionProcess public: static inline void f() statement1; / true case;class ConditionProcess public: static inline void f() statement2; / false case;/ Replacement for if/else statement:ConditionProcess :f();,if (condition) statement1;else statement2;,Com
14、pile-time能够确定condition的值,Template技术 代替runtime的switch,/ Class declarationstemplateclass SwitchProcess public: static inline void f() default-statement; ;class SwitchProcess public: static inline void f() statement1; ;class SwitchProcess public: static inline void f() statement2; ;/ Replacement for sw
15、itch(i) statementSwitchProcess :f();,int i;switch(i) case value1: statement1; break; case value2: statement2; break; default: default-statement; break;,Template技术 代替runtime的do循环,templateclass DoProcess private: enum go = (I-1) != 0 ;public: static inline void f() statement; DoProcess :f(); ;/ Specia
16、lization provides base case for recursionclass DoProcess public: static inline void f() ;/ Equivalent loop codeDoProcess :f();,int i = N;do statement; while (-i 0);,Template技术 代替runtime的临时变量,templateclass countBits enum bit3 = (N ,int countBits(int N) int bit3 = (N ,Template技术 计算 Compile-time functi
17、ons,一般原则:局部变量用enum类型循环转化为递归,结束条件为一个特化版本也可以是多重循环,需要用到部分特化特性条件分支用模板特化解决效果:以类型为基础,实现各种操作例如sin x = x - x3/3! + x5/5! - x7/7! + 在编译时刻求pow(x,y),即x的y次方,Template技术 计算pow(x,y),templatestruct ctime_pow enum result = X*ctime_pow:result ;templatestruct ctime_powenum result = 1;用法:const int z = ctime_pow:result;
18、,Trait技术,定义一些“函数”,这些函数的参数和返回值都是类型(type),而不是数据(data)例如:对于一个数组类,它的元素类型和平均数的类型不一定相同,可以用一个trait class来建立这种映射关系对应关系Average_type(T) - TAverage_type(int) - floatTrait的使用:Average的实现,Partial evaluation,一个程序的计算分为两个部分静态计算:在编译时刻执行动态计算:在运行时刻执行例如,计算立方体的体积,Template技术 模板类作为基类,某种程度上可以代替模板特化templateclass String : pub
19、lic Array public :/ additional functionalitybool operator=(const String,Template技术 以模板参数作为基类,允许用户把自己的类插入到类层次的中间用户提供基类,类库使用基类templateclass Deriving : public Base ,C+ as a two-level language,将type当作first-class value来对待例如一种做法: 下面的句子typedef T T_average;相当于typedef T_average = T;实现了类型的赋值,Template技术 typeli
20、stfrom Modern C+ Design,以类型作为元素构成链 template struct Typelist typedef T Head; typedef U Tail; ;,例如Length操作 template struct Length; template struct Length enum value = 0 ; ; template struct Length enum value = 1 + Length:value ; ;,typelist各种操作LengthTypeAtIndexOfAppendEraseReplaceMostDerived.,Template技术
21、 typelist(续一),typelist用法#define TYPELIST_1(T1) Typelist#define TYPELIST_2(T1, T2) Typelist#define TYPELIST_3(T1, T2, T3) Typelisttemplate class Unit class GenScatterHierarchy, Unit : public GenScatterHierarchy , public GenScatterHierarchy;template class Unit class GenScatterHierarchy : public Unit;t
22、emplate class Unit class GenScatterHierarchy;,Template技术 typelist(续二),GenScatterHierarchy用法template class HolderT m_value;,typedef GenScatterHierarchy MyTypeTree,Template技术:动态绑定 模拟虚函数多态性,templateclass Array public :virtual int Compare(const Array ,templateclass Array public :.bool operator ,policy,A
23、liases :strategy, behavior class, trait, aspect在设计供重用的类或者组件的时候,尽可能地把细节抽象出来,虽然这些细节遍布各处,但它们本身并不构成耦合对问题的垂直分解和水平分解,Policy(续一),想法:用policy来配置一个类或者组件把影响问题的因素分解成几个不相关的方面,并且用policy class来表达,例如创建策略线程模型policy之间尽可能不相关一旦有关联,就可能产生一些制约因素,例如引用计数策略(RefCountPolicy)和存储策略(StoragePolicy)policy类与host类之间可以在runtime进行组合,也可以
24、在compile-time进行组合,Policy(续二),用模板参数作为policy class编译器在compile-time对host class进行配置例如:templateclass Widget template class CreationPolyclass WidgetManager,Policy(续三),Policy组合,用m+n个类组合成n*m种可能,例如:template class CheckingPolicy, template ThreadingModelclass SmartPtr; typedef SmartPtr SafeWidgetPtr;templatest
25、ruct EnsureNotNull static void Check(T* ,Policy(续四),用模板实现Policy的意义在compile-time配置host class,有助于产生更为高效的代码,更加generic以类为基础配置一个类,所以policy往往包含静态方法,即class-level的方法在设计可重用类或者组件的时候,根据需要提取出policy,并确定policy的接口实现类似hook的思想,由用户提供具体的policy class,从而把有些行为往后延迟缺点:要求使用者对于policy有非常的了解,知道每一种策略会影响到问题的哪些方面,Visitor模式(GoF),V
26、isitor模式改进,ConcreteElementAAccept(EleVisitor)OperationA,ConcreteElementBAccept(EleVisitor)OperationB,EleVisitor,ElementAVisitor,ElementBVisitor,MyConcreteVisitor,信息结构,Visitor结构,Lazy技术,Lazy Initialization,第一次被访问时初始化SingletonCOW(Copy on write),第一次被写入时才拷贝Lazy Protocol:DCOM协议,Double-Checked Locking Patt
27、ern,假设mutex是一个Mutex对象,现在需要对pInstance的访问进行同步,一种方案是Singleton,Double-Checked Locking Pattern(续一),前述的方案效率比较低,只有一次new操作需要保护,其他的只读访问不必同步保护,改进:Singleton,问题:race condition又出现了,Double-Checked Locking Pattern(续二),Double-Checked Locking Pattern :Singleton,Table-driven pattern,代替runtime switch问题:从文件中读入一组以CShape
28、为基类的对象,传统的做法:ReadWord(stream, ,Table-driven pattern(续),维护一张表(typeid, fnCreator)根据typeid查找到创建函数,然后创建对象,示例代码如下:ReadWord(stream, 在MFC/ATL大量用到table-driven的技术用多维表可以实现double-dispatch或者multi-dispatch技术,用类层次代替union,Union最主要的用法Discriminated union: tag + union例如VARIANT可以用一个类层次来替代union,这对于那些不支持union的语言很有意义比如Ja
29、va使用类层次的好处:类型安全性代码简洁、清晰容易扩展反映了类型之间的本质关系(OO)参考:Effective Java,举例:用类层次代替union,Java代码,代替enum结构,Enum类型的缺点其中的常量没有自己的名字空间难以扩展,使用enum来定义的类型非常脆弱多方难以合作添加常量与其他类型(比如字符串)不便于转换typesafe enum pattern, from “Effective Java”基本思想:定义一个类来代表单个元素,并且不提供任何公有构造函数。相反,提供公有的静态final域,可枚举类型中的每一个常量都对应一个域,framework,领域工程单个系统 一类系统有较
30、强的抽象能力组件库提供定制功能,允许开发人员对于框架主体部分进行修改不同层次上的framework基于二进制代码的framework,例如MMC基于源代码的framework,例如MFC,基于二进制的framework,接口:为应用中的组件提供二进制接口以对象形式封装以功能为单位粒度大而全的接口小型接口,允许动态发现新的接口通信模型用户组件与框架进行通信用户组件之间如何通信?通过框架传递信息通过框架建立直通模型,基于源代码的framework,接口:一般为抽象类,用户提供虚函数的实现,并注册到主框架中用户定制的余地比较大通信模型用户组件与框架进行通信用户组件之间容易建立起直通途径,从派生类传播
31、类型到基类的一种模式,意图:基类有时需要根据子类的类型执行一些功能,而基类又不可能直接得到子类的静态类型这对于generic programming非常重要,因为编译器要靠静态类型来实例化模板(函数或者类)解决方案用虚函数不能解决问题 runtime多态性在子类中插入一个函数,由该函数调用模板函数或者模板类,或者该函数调用基类中的模板成员函数仅对基于源代码的framework适用,Framework举例,为报社提供一套framework,Snap-In管理器,FrameSite,FrameSite,FrameSite,SnapIn对象,SnapIn对象,SnapIn对象,Security管理器
32、,Database管理器,UI管理器,SnapIn仓库,IFrameSite,ISnapInfo,SnapIn DLL,SnapIn DLL,SnapIn DLL,可重用类库的设计(一),在所有的系统设计中,可重用类库的设计是难度比较大的,要做到:使用:灵活性和易用性功能:广泛性和效率经验非常重要实现同样的功能会有许多不同的道路,如何选择?效果怎么样?类库的基础是否使用其他的类库?是否使用特殊的平台和编译环境?参考成功的类库起点要高,可重用类库的设计(二),接口的设计这是类库的关键,会影响到类库的使用接口的类型:C/C+大而全的接口并不理想接口的语义一定要清晰facade模式内存管理保证内存分
33、配和释放的一致性使用要方便out参数的资源由谁来申请?谁知道size?是否使用自定义的内存分配器,例如针对小对象的分配器,可重用类库的设计(三),使用各种模式模式是经验,成功的典范policy模式允许使用者定制类结构型模式有助于建立起更加合理的结构模型,而不至于层次错综复杂行为型模式有助于各个类之间有更好的协作模型创建型模式可以提供各种合理的创建机制模板类库的特殊性利用模板类型实现compile-time的预处理熟悉编译器的特性控制模板生成代码,可重用类库的设计(四),行为前置和延后在基类中提供缺省的实现纯虚函数 强制子类提供实现利用functor或者函数指针要求(必须)子类调用父类的实现用宏
34、来封装代码代码风格类库的优化优化需要用到内部知识,是否暴露这些知识允许使用者用policy进行配置,用不同的实现配置类类似于policy的思想,在细节点上用开关进行控制,可重用类库的设计(五),类库的调试类库内部调试,使用assert支持类库的测试比应用系统的测试更加严格类库的发行是否提供源代码?文档编译设置,可重用类库的设计(六),举例:MFC/ATLMFC同时也具有源代码框架的结构传统意义上的C+类库,对Win32进行了封装以便于使用为主要目标,优化较少用到了许多patterns,吻合Windows应用模式涉及到许多类库设计技术与Wizard结合产生基本代码ATL用到了generic programming中许多新的技术模板技术优化比较突出,总结,C+基础COM基础COM扩展COM+Design Patterns软件设计技术,