《软件设计模式》配套教学课件_第1页
《软件设计模式》配套教学课件_第2页
《软件设计模式》配套教学课件_第3页
《软件设计模式》配套教学课件_第4页
《软件设计模式》配套教学课件_第5页
已阅读5页,还剩220页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

《设计模式》第一部分设计模式基础§1.1面向对象设计与复用§1.2设计的模式§1.3类设计的UML表示§1.4OO设计的原则§1.5设计模式说明分类方法四个要素§1.1面向对象设计与复用面向对象设计的层次框架级设计类设计代码设计类设计中考虑哪些问题?如何进行类设计类设计中难点在于—变化的存在变化与维护性类设计考虑的问题类的组织与表示类的发现聚类分析类的再抽象类的拆分类的可见性类的复用性行为的组织与表示行为的参与者行为的分组与接口行为的分解行为的可见性行为的返回结果行为的差异属性的组织与表示本征属性可计算属性复合属性只读/只写属性不变属性类变量与类属性设计时属性与运行时属性变化与复用变化职责的变化(接口、功能的变化)实现的变化(数据表示、行为的变化)变化的适应方式修改既有代码的缺点既有代码的获取问题改变实现的顾虑改变接口的顾虑扩展既有代码继承方式扩展依赖方式扩展关联方式扩展聚合方式扩展组合方式扩展复用的价值面向对象的复用mainClassClassClassClass§1.2模式的层次框架(Framework)MVC及Document/ViewCOM/DCOM/EJB/…其它(Spring、Hibernate等)设计模式微模式微模式(MicroPattern)例If(ord==0){}elseif(ord==2){}elseif(ord==60){}else{}switch(ord){case0: break;case‘A’:break;case‘\0’:break;default:break;}§1.3类间关系及UML表示关联关系(水平关系,类级关系)普通关联部分/整体关联依赖关系(水平关系,实例级关系)泛化关系(垂直关系)父类和子类抽象类和具体类实现关系接口类与实现类模版与模版类普通关联双向关联关系classA{private:B*pB1;B*pB2;};classB{private:A*pA;};普通关联双向多对多关联关系单向关联(相识关系)单向关联关系classA{private:B*pB;};classB{};组合(合成)关系1)B是A的组成部分;2)A负责B的生存与消亡如:人由头、颈、躯干、四肢组成。例:classA{Public:A():pB(newB){}~A(){deletepB;}};聚集(聚合)关系1)B是A的组成部分;2)但A不负责B的生存与消亡。即A存在时,B可以不存在;B存在时,A也可以不存在;如:计算机包括CPU,内存,网卡等。其中的网卡就可独立依赖关系(实例级关联)#include“B.h”classA{public:voidFunc(B&b);};泛化关系classA1{};classB1:publicA1{};实现关系classIA{Public:virtualvoidfunc1()=0;virtualvoidfunc2()=0;};classA:publicIA{public:virtualvoidfunc1(){}virtualvoidfunc2(){}};§1.4OO设计的原则基本原则抽象与封装原则接口编程,而不是针对实现编程组合优先原则(而不是继承)单一职责原则(Thesingleresponsibility)

开闭原则(Open-ClosePrinciple)

里氏替换原则(TheLiskovsubstitution

)依赖倒转原则多接口分离原则迪米特法则(委托而不是直接交互)基本原则抽象与封装原则分离稳定与变化封装变化抽象变化接口针对接口编程,而不是针对实现编程组合优先原则(而不是继承)分离稳定与变化职责是否变化实现是否变化ClassClock{Public:voidSetDate(){}voidSetTime(){}voidDraw(){DrawDate();DrawTime();}Protected:voidDrawDate(){}voidDrawTime(){}private:Datedt;Timetm;};classIClock{public:virtualvoidSetCurrent();virtualvoidDraw();};ClassBaseClock:publicIClock{public:voidSetCurrent(){ SetDate(); SetTime();}voidSetDate(){}voidSetTime(){}voidDraw(){ DrawDate(); DrawTime(); }protected:voidDrawDate(){}voidDrawTime(){}private: Datedt; Timetm;};针对接口编程ClassMyClass{Private:IClock*aClock;//不采用BaseClock*aClock;};组合优先classA{//…};classEA{private:A*aA;};classEA:publicA{};单一职责原则(Thesingleresponsibility)类的职责不要过多单一职责可有效降低类间的耦合度,提高内聚度职责的划分不可过于机械开闭原则(Open-ClosePrinciple)对扩展开放,对修改关闭禁止修改,允许扩展这是我们的追求!!!里氏替换原则(TheLiskovsubstitution

)任何出现父类的地方,均可用子类替换;必须正确地使用继承限制RTTI的使用依赖倒转原则倒转是指:与结构化设计方法正好相反;结构化中依赖:高层依赖于底层具体实现;OO中依赖:高层只依赖于底层的抽象类和接口;即底层的实现类依赖抽象类和接口。依赖倒置说明多接口分离原则一个接口类的职责不要太多可分为多个接口使变化更灵活,提高移植性使用多接口迪米特法则(委托而不是直接交互)交互过多,将增加类的耦合度引入中间类,负责交互工作,降低耦合度§1.5设计模式说明什么是设计模式分类方法行为型模式结构型模式创建型模式四个要素模式名称应用场景解决方案效果及说明对象的生命周期类模版模版类具体类类对象实例化初始化类行为销毁对应于结构型模式

(关注如何分解、组织、封装各个类)对应于创建型模式对应于行为型模式第二部分行为型设计模式策略模式(StrategyPattern)状态模式(StatePattern)中介者模式(MediatorPattern)迭代器模式(IteratorPattern)命令模式(CommandPattern)责任链模式(ChainofResponsibilityPattern)观察者模式(ObserverPattern)访问者模式(VistorPattern)备忘录模式(MementoPattern)解释器模式(InterpreterPattern)模板方法模式(TemplateMethodPattern)行为的变化变化数据表示的变化行为的变化行为的变化与适应接口变化实现的变化静态性变化动态性变化交互上的变化数据表示的变化数据的类型、数量、可访问性、组织形式等classOne{public:

virtual~One(){…..}virtualvoidDo(){….}

private:intx;inty;

Two*pTwo;};接口的变化功能的增加功能的减少(OO均不支持)参数个数及类型的变化可访问性的变化等等classOne{public:

virtual~One(){…..}virtualvoidDo(){….}

private:intx;inty;

};classOne{public:

virtual~One(){…..}virtualvoidDo(){….}

virtualvoidDo2(){….}private:intx;inty;

};实现中的静态性变化静态性变化体现类模版的实例化具体类的行为静态性template<typenameT>classOne{public:

virtual~One(){…..}virtualvoidDo(T&aT){….}

private:T*pt;

};#include“Two.h”One<Two>aOne;具体类的行为静态性一旦具体类确定了,类的行为就确定了。即无论该类有多少个对象,各对象的行为完全一致,且在实例化时就确定了,而在运行期间不会改变。举例:Do1的实现变化;Do2的实现变化只有Do1的实现改变Do1和Do2同时变化具体类行为的动态性可以动态改变行为的执行结果根据:环境上下文、当前配置文件、系统状态客户的主观意愿,选择的策略等交互上的变化需要直接交互/间接交互?依赖型交互/关联型交互?交互的主动方和被动方?行为模式主要针对行为的静态性变化及适应行为的动态性变化及适应交互上的变化及使用2.1策略模式(StrategyPattern)举例:一个扑克牌游戏中的玩家(Player),其行为:出牌。在其玩的过程中,若嫌电脑太笨,可能加大电脑的AI;若总是玩不过电脑,便可能选择较低难度的出牌方式。2.1.1策略模式意图定义多个实现或实现的一部分,并一一封装起来。在行为的动态执行过程中,可以替换各实现。这样,各实现可独立于使用者(客户)而变化。2.1.2例2.1.3适用性只是行为上有差异,差异部分可动态替换(区别于静态变化适应方式)差异部分可能有更多的变体实现中以多个条件语句的形式区别不同的实质行为。2.1.4类图结构2.1.5策略模式效果封装一部分实现细节允许在不新建上下文(Context)的情况下,改变行为。允许相同的行为有不同的实现,而且可动态地选择并改变。2.1.6补充说明比较静态、动态行为变化可代替条件分支或case语句。具体策略的建立与绑定Context与Strategy间的双向关联2.2状态模式(StatePattern)举例:

一个TCPConnecttion,在接到客户请求时,将根据当前自身的状态,做出不同的反应。如,在Establised、Listening、Closed状态下,对Open、Close、Acknowledge等请求会有不同的反应。2.2.1状态模式意图使行为自动适应状态的改变去掉判断状态的分支语句2.2.2例2.2.3状态模式类图2.2.4状态模式效果将与行为相关的状态,单独抽象出来。状态改变时,使用者不用判断状态再执行相应的行为。状态的改变,可放在具体状态中实现,也可放在上下文(Context)中实现。状态对象的创建与销毁比较策略模式和状态模式2.2.5对比策略模式一个扑克牌游戏中的玩家(Player),其行为:出牌。在其玩的过程中,若嫌电脑太笨,可能加大电脑的AI;若总是玩不过电脑,便可能选择较低难度的出牌方式。一个扑克牌游戏中的玩家(Player),其行为:出牌。在其玩的过程中,电脑玩家若快输了,可能采用激进的出牌方式;若基本赢定了,便可能选择较为保守的出牌方式。2.3中介者模式(MediatorPattern)例:

一个系统中有多种类型的多种对象相互作用,共同完成系统的功能。2.3.1中介者模式意图降低各类/对象间的耦合度,使得各类可独立地变化,增加复用性。使用一个中介对象封装各对象间的交互,并集中处理交互过程。2.3.2中介者模式类图2.3.4中介者模式适用性多个对象定义良好,但通信复杂。此时相互间的依赖关系和关联关系复杂、混乱,不易理解。一个对象关联其它很多对象,并与相互通信,导致该对象难以维护和复用。一个行为的实现,需要其它多个类型的多个对象共同参与完成,但又不愿生成过多的子类。2.3.5中介者模式效果好处将多对多的交互,改变成一对多的,易于维护和理解降低各Colleague间的耦合度集中处理对象间的交互和通信,不破坏对象的复用性不足大大增加了中介者类的复杂度中介者类难以复用2.3.6中介者模式的实现中介者与同事间通常是双向关联的。同事对象的创建与销毁抽象中介者的使用中介者与同事间的通信2.4观察者模式(ObserverPattern)又名:订阅-发布模式例:一个时钟模型,当时间改变时,通知各显示界面,如以数字形式显示,或以表盘形式显示。2.4.1观察者模式意图多个对象间是一种一对多的关系;当一个对象的状态改变时,所有依赖于它的对象都将得到通知,并自动更新;2.4.2观察者模式结构2.4.3观察者模式变体2.4.4观察者模式效果目标与观察者间解耦(只在抽象层耦合)支持广播通信不足:更新可能出现意外2.4.5观察者模式的实现问题目标与观察者间的关联管理可直接关联,也可将关联关系存入一个Map表中目标可以多个。即二者为多对多关系。更新的触发2.4.6例子代码classSubject;classObserver{public:

virtual~Observer();virtualvoidUpdate(Subject*theChangedSubject)=0;};classSubject{public:Subject();virtual~Subject();virtualvoidAtach(Observer*obj){observers->Append(obj);}virtualvoidDetach(Observer*obj){observers->Remove(obj);}virtualvoidNotify(){ListIterator<Observer*>i(observers);for(i.First();!i.IsDone();i.Next()){i.CurrentItem()->Update(this);}}private:List<Observer*>*observers;};//具体的目标类ClockTimerclassClockTimer:publicSubject{public:ClockTimer();virtualintGetHour();virtualintGetMinute();virtualintGetSecond();

voidTick(){//记录当前时间

Notify();

}};//具体的观察者类DigitalClockclassDigitalClock:publicObserver{public:

DigitalClock(ClockTiemr*theSubject){subject=theSubject;subject->Attach(this);}virtual~DigitalClock(){subject->Detach(this);}virtualvoidUpdate(Subject*theChangedSubject){if(theChangedSubject==subject){Draw();}}virtualvoidDraw(){inth=subject->GetHour();intm=subject->GetMinute();ints=subject->GetSecond();

//绘制时钟,略

}private:ClockTimer*subject;};客户代码:ClockTimer*timer=newClockTimer;AnalogClock*analogClock=newAnalogClock(timer);DigitalClock*digitalClock=newDigitalClock(timer);2.5访问者模式(VisitorPattern)意图:针对一个结构中(如树、链表、集合等)的各元素进行操作时,元素的类型可能不尽相同。

1)如何在操作时,去掉类型的检测和判断。

2)如何允许添加新的操作?2.5.1例子classAnimal{};classCat:publicAnimal{public:

virtualvoidSleep();};

classDog:publicAnimal{public:

virtualvoidEat();

virtualvoidRun();};voidmain(){Vector<Animal*>*

animals=newVector<Animal*>;animals->Add(newCat);animals->Add(newDog);Animal*an;foreach(

aninanimals){

if(dynamic_cast<Cat*>(an)!=0){

((Cat*)an)->Sleep();

}elseif(dynamic_cast<Dog*>(an)!=0){

((Dog*)an)->Eat();

}}问题:1)if-else多了不易处理2)类型的检查(违背里氏替换原则)3)Dog增加一个操作Run,怎么办?4)增加一个接口Jump,怎么办?针对问题1)和2)修改Animal及子类修改Animal及子类class

Animal{public:

virtualvoidDo();};classCat:publicAnimal{public:

virtualvoidDo(){

Sleep();}

virtual

voidSleep();};classDog:publicAnimal{public:

virtualvoidDo(){Eat();}

virtualvoidEat();};

classAnimal{};classCat:publicAnimal{public:

virtualvoidSleep();};

classDog:publicAnimal{public:

virtualvoidEat();

virtualvoidRun();};foreach(

aninanimals){

if(dynamic_cast<Cat*>(an)!=0){

((Cat*)an)->Sleep();

}elseif(dynamic_cast<Dog*>(an)!=0){

((Dog*)an)->Eat();

}}foreach(

aninanimals){

an->Do();}可以。但合理吗?Sleep,Eat是一个行为?!若再增加一个Run操作呢?foreach的操作改变了呢?分离稳定与变化部分稳定:结构(Animal,Cat,Dog)变化:操作(Sleep,Eat,Run,…)结构部分(不变,这里简写)classAnimal{};classCat:publicAnimal{};classDog:publicAnimal{};操作部分:(3个不同实现)SleepForCatEatForDogRunForDog如何分组?按Cat、Dog类型分?还是按功能分?按猫狗的类型对操作分组class

Operate{public:

virtual

voidSleep();

virtual

voidEat();

virtual

voidRun();};classCatOperate

:public

Operate{public:

virtual

voidSleep(){/*

Sleep();

*/}

virtual

voidEat(){}

virtual

voidRun(){}};class

DogOperate

:public

Operate{public:

virtual

voidSleep(){}

virtual

voidEat(

){/*

Eat();*/}

virtual

voidRun(){/*Run();*/}};则main中的改为:foreach(

aninanimals){//创建具体Operate,

//需要先确定an是Cat?Dog?

operate->Sleep();operate->Eat();}这样不行。还得先确定an的具体类型,才能确定执行的Sleep是哪个类的。

按功能对操作分组1)classVisitor{public:

virtual

void

VisitCat

(Cat*){}

virtual

void

VisitDog

(Dog*){}};

classSleepVisitor

:public

Visitor{public:

virtual

void

VisitCat

(Cat*cat)

{cat->Sleep();

}

};classEatVisitor

:public

Visitor{public:

virtual

void

VisitDog

(Dog*dog)

{dog->Eat();}};classRunVisitor

:public

Visitor{public:

virtual

void

VisitDog

(Dog*dog)

{dog->Run();

}

};foreach(

aninanimals){

if(dynamic_cast<Cat*>(an)!=0){

((Cat*)an)->Sleep();

}elseif(dynamic_cast<Dog*>(an)!=0){

((Dog*)an)

->Eat();

}}按功能对操作分组2)SleepVisitor*v1=newSleepVisitor;EatVisitor*v2=newEatVisitor;foreach(

aninanimals){

DoSome(v1,an);

DoSome(v2,

an);

v1->VisitCat(an);//????

v2->VisitDog(an);

//?????

//还不知道an是Cat,还是Dog呢!!}classAnimal{public:

virtualvoidAccept(Visitor*v);

//....};classCat:publicAnimal{public:

virtualvoidAccept(Visitor*v){

v->VisitCat(this);}

//....};classDog:publicAnimal{public:

virtualvoidAccept(Visitor*v)

{

v->VisitDog(this);}

//....};按功能对操作分组3)修改Animal,添加Accept()SleepVisitor*v1=newSleepVisitor;EatVisitor*v2=newEatVisitor;foreach(

aninanimals){

an->Accept(v1);

an->Accept(v2);

}foreach(

aninanimals){

if(dynamic_cast<Cat*>(an)!=0){

((Cat*)an)->Sleep();

}elseif(dynamic_cast<Dog*>(an)!=0){

((Dog*)an)

->Eat();

}}2.5.2访问者模式适用性对象包含很多子对象或元素,但各元素有不同的接口,但在操作这些元素时,希望做一些涉及或依赖于具体元素类型的操作。对象结构很少改变,但常需要在此结构上定义新操作。2.5.3访问者模式使用方法分离结构和操作。将操作按功能分类(而不是按结构分类)按功能定义Visitor类及子类在结构Element中添加Accept。对Element对象,执行操作。按功能定义Visitor类及子类class

Func1Visitor:public

Visitor{public: virutalvoidVisitElementA(ElementA*a)

{

a->doFunc1();

}

virutalvoidVisitElementB(

ElementB*b)

{

b->doFunc1();

}

virutalvoidVisitElementC(

ElementC*c)

{

c->doFunc1();

}

};class

Func2Visitor:public

Visitor{public:

virutalvoidVisitElementA(ElementA*a)

{

a->doFunc2();

}

virutalvoidVisitElementB(

ElementB*b)

{

b->doFunc2();

}

virutalvoidVisitElementC(

ElementC*c)

{

c->doFunc2();

}

};public

Visitor

{public:virutalvoidVisitElementA(ElementA*a)=0;

virutalvoidVisitElementB(

ElementB*b)=0;

virutalvoidVisitElementC(

ElementC*c)=0;};

class

BaseElement{public:

virtualvoidAccept(Visitor*v)=0;//…..};class

ElementA:publicBaseElement{public: virtualvoidAccept(Visitor*v)

{

v->VisitElementA(this);}

//.....};class

ElementB:publicBaseElement{public:

virtualvoidAccept(Visitor*v){

v->VisitElementB(this);}

//.....};在结构Element中添加Accept()

需执行操作Func1时,可Visitor*v=newFunc1Visitor;elem->Accept(v);需执行操作Func2时,可Visitor*v=newFunc2Visitor;elem->Accept(v);访问结构中的元素elem时

2.5.4访问者模式结构2.6模板方法模式

(TemplateMethodPattern)意图:不改变操作的主体结构或过程,将其中的特定步骤或过程延迟到子类中实现。2.6.1例子classProcessFile{public:

voidProcess(){

OpenFile();

DoFile();

CloseFile();

}protected:

virtualvoidDoFile(){}

virtualvoidOpenFile(){}

virtualvoidCloseFile(){}};classMyProcessFile:publicProcessFileprotected:

virtualvoidOpenFile()

{

//......

}

virtualvoidDoFile(){

//......

}};2.6.2模板方法模式适用基本过程是稳定的特定的步骤易变或有待子类确定。若多个步骤易变,可能导致子类数量的快速增长可以和策略模式、状态模式等结合使用2.7职责链模式

(ChainofResponsibility)意图:给多个对象处理请求的机会解耦发送者和接收者间2.7.1例子classHelpHandler{public:

HelpHandler(HelpHandler*next)

:handler(next)

{}

virtualvoidHandleHelp()

{handler->HandleHelp();}

protected:

HelpHandler*

handler;};classWidget:publicHewlpHandler{public:

Widget

(HelpHandler*next)

:HelpHandler(next){

}

virtualvoidHandleHelp(){

if(canHandle){

//HandleCode

}else{

handler->HandleHelp();

}}};

classButton:public

Widget

{public:

Button

(HelpHandler*next)

:

Widget

(next){

}

virtualvoidHandleHelp(){

if(canHandle){

//HandleCode

}elseif(handler){

handler->HandleHelp();

}};

voidmain(){

Button*btn=newButton(NULL);

Window*win=newWindow(btn);

win->HandleHelp();

deletewin;

deletebtn;}2.7.2责任链结构2.8命令模式(CommandPattern)意图:将一个请求(或动作、命令等)封装,这样的请求就可以带参数进行实例化了。因此,同一个请求,不同的参数,可以是不同的实现结果。请求可能增加请求可以是请求队列请求可以被记录、撤销等。2.8.1例classReceiver{

};classReceiverA:publicReceiver{};classReceiverB:publicReceiver{};classReceiverC:publicReceiver{};classReceiverD:publicReceiverC{};classRequester{public:

virtualvoidDoAction1(ReceiverA*a);

virtual

void

DoAction1(ReceiverB*b);

virtual

void

DoAction2(ReceiverD*d);

};问题:

1)增加新的ReceiverA2,怎么办?

2)同时增加新的RecieverD2,又怎么办?

3)增加一个新的Action,它是由

DoAction1(ReceiverA*a)和

DoAction1(ReceiverB*b)顺序组成的,又怎么办?

4)需要对每个Action,都做日志记录,怎么办?

5)需要对每个Action,都可以做撤销操作,怎么办?

将Requester的DoAction及参数变化单独封装起来:classRequester{public:

virtualvoidDoAction(Command*comd)

{

comd->Excute();}};classCommandAction2:publicCommand{public:

CommandAction2(ReceiverC*rec)

:receiver(rec){}

virtualvoidExcute()

{

receiver->DoSomething2();}private:

ReceiverC

*

receiver;

};由Command区分Action及Receiver:classCommand{public:

virtualvoidExcute()=0;};classCommandAction1:publicCommand{public:

CommandAction1(Reciveiver*rec)

:receiver(rec)

{}

virtualvoidExcute()

{

receiver->DoSomething1();}private:

Receiver

*

receiver;

};队列(例如由两个Command组成的请求队列)classMacroCommod:publicCommand{public:

MacroCommand(

Command

*comand1,

Command

*command2)

:

cmd1(command1),cmd2(command2)

virtualvoidExcute()

{

cmd1->Excute();

cmd2->Excute()

}

private:

Command

*cmd1;

Command

*cmd2;};2.8.3命令模式优缺点好处:◆容易构造一个命令队列◆便于以日志形式记录命令的执行情况◆保留并存储命令执行中的各种信息,可以实现命令的撤销和重做◆便于增加新的命令缺点:可能会有过多的具体命令类存在2.8.4命令模式结构2.9小结基于各种原因导致行为差异策略模式状态模式模板方法模式命令模式通知/访问多个对象责任链模式观察者模式访问者模式交互复杂中介模式第三部分结构型设计模式桥接模式(BridgePattern)适配器模式(AdpterPattern)合成模式(CompsitePattern)门面模式(FacadePattern)装饰模式(DecoratorPattern)代理模式(ProxyPattern)享元模式(FlyweightPattern)3.1桥接模式(BridgePattern)classA{public:

virtual~A();

virtualvoidf();

virtualvoidg();private:

int

x;

int

y;};变化的三个方向:1)接口的变化2)实现的变化3)属性的变化(本质上,还是实现的变化)适应单个方向的变化容易组合和继承方式均可适应接口变化方法classA{public:

virtual~A();

virtualvoidf();

virtualvoidg();protected:

int

x;

int

y;};classNewA:publicA{public:

virtual~NewA();

virtualvoidh();};classNewA{public:

NewA(A*oldA):pa(oldA){}

virtual~NewA();

virtualvoidf(){pa->f();}

virtualvoidg(){pa->g();}

virtualvoidh();private:

A

*pa;};适应实现变化方法classA{public:

virtual~A();

virtualvoidf();

virtualvoidg();protected:

int

x;

int

y;};classNewA:publicA{public:

virtual~NewA();

virtualvoidf(){

/*新实现*/

}};classNewA{public:

NewA(A*oldA):pa(oldA){}

virtual~NewA();

virtualvoidf(){

/*新实现*/

}

virtualvoidg(){pa->g();}protected

:

A

*pa;};classNewA{public:

NewA(

ImpF*f,ImpG*g

)

:pf(f),pg(g){}

virtual~NewA();

virtualvoidf(){

pf->f();}

virtualvoidg(){pg->g();}private:

ImpF*pf;

ImpG*pg;};classImpF{public:

virtual~ImpF();

vritualvoidf()=0;};classImpF1:publicImpF{public:

virtual~ImpF1();

vritualvoidf(){}

};两个方向同时变化的适应单一使用组合或继承的不足结合组合和继承的方式分离变化用组合关联两个方向的变化使单个方向的变化独立出来(独立变化)例第一步:分离接口和实现class

A{public:

virutal~A();

virtualvoidf();

virtualvoidg();};

classImpA{public:

virtual~ImpA();

virtualvoidf();

virtualvoidg();protected:

int

x;

int

y;};第二步:用组合连接接口和实现class

A{public:

virutal~A(ImpA*p):impA(p){}

virtualvoidf(){impA->f();}

virtualvoidg(){impA->g();}private:

ImpA

*impA;};classImpA{public:

virtual~ImpA();

virtualvoidf();

virtualvoidg();protected:

int

x;

int

y;};第三步:使接口和实现的变化独立class

A{public:

virutal~A(ImpA*p):impA(p){}

virtualvoidf(){impA->f();}

virtualvoidg(){impA->g();}private:

ImpA

*impA;};classImpA{public:

virtual~ImpA();

virtualvoidf();

virtualvoidg();protected:

int

x;

int

y;};class

NewA:pubicA{public:

virutal~NewA(ImpA*p):A(p){}

virtualvoidh(){}};classImpA1:publicImpA{public:

virtualvoidf(){/*新实现*/}};继承继承组合3.1.2效果分离了接口及其实现使得各部分可独立变化、扩展可对客户隐藏实现部分也称Handle模式/Handle-Body模式3.1.3结构3.2适配器模式(AdapterPattern)已有现成的两个类簇-Student和Teacher类簇;希望创建一些新的实例-具有学生的功能,但这些功能又用到教师的功能;例:学生、教师classIStudent{public:

virtual~IStudent();

virtualvoid上课();

virtualvoid休息();

};classTeacher{public:

virtual~Teacher();

virtualvoid授课();

virtualvoid玩();

};学生可有本科生、硕士研究生、博士研究生等;现增加一类在职学生----本身也是教师。这时,在职学生的上课就是教师的授课;怎么才能将教师,当做学生来使用呢?问题接口的不一致性原接口的不可更改性解决方式:类的适配器方式对象适配器方式类的适配器模式classIStudent{public:

virtual~IStudent();

virtualvoid上课()=0;

virtualvoid休息()=0;

};classTeacher{public:

virtual~Teacher();

virtualvoid授课();

virtualvoid玩();

};class在职学生:publicIStudent,privateTeacher{public:

virtual~

在职学生

();

virtualvoid上课(){授课();

}

virtualvoid休息(){玩();}

};对象适配器方式classIStudent{public:

virtual~IStudent();

virtualvoid上课()=0;

virtualvoid休息()=0;

};classTeacher{public:

virtual~Teacher();

virtualvoid授课();

virtualvoid玩();

};class在职学生:publicIStudent{public:

在职学生(Teacher*t):tc(t){}

virtual~

在职学生

();

virtualvoid上课(){tc.授课();

}

virtualvoid休息(){tc.玩();}

private:

Teacher*

tc;

};3.2.2效果在不改变原有类的前提下,调整原有类的接口适用性:使用已有的类,但类的接口不符合需要;对象适配器,通常比类适配器更灵活;3.2.4类适配器结构3.2.5对象适配器结构3.3合成模式(CompsitePattern)一个树形结构:树枝树叶树枝树枝树叶树枝树叶树枝树枝树叶树枝树叶树枝树枝树叶节点的关系表示根节点(特殊的树枝/叶子节点)树枝节点叶子节点是否有更一般化的表示呢?即不论哪种节点,访问的方法最好能一致些呢?一般化表示子节点的管理AddChild(),RemoveChild(),GetChild(int),GetChildren()等只对树枝节点有意义这些管理子节点的操作放哪个类里呢?放Node中(透明式)放BranchNode中(安全式)3.3.2透明式合成模式结构(1)透明式合成模式结构(2)安全式合成模式3.3.3例子一个集团公司:下设多个部门,如办公室、财务处、基建处、人事处等;同时还下设多个分公司,如北京分公司、广东分公司等;各分公司,也可以下设多个部门和多个分公司,如广东分公司,可能下设财务处、投标办、广州分公司、深圳分公司、珠海分公司等。3.4门面模式(FacadePattern)一个子系统:内部有许多类,该子系统通过这些类和它们之间的交互作用,为客户提供相应的功能。

CBDA用户1用户2用户必须清楚子系统中的各部分的职责;用户不关心子系统的实现,而只是应用子系统中的已有功能;用户的访问,通常是单向的;CBDA用户1用户2门户3.4.2结构Facade3.4.3效果对用户隐藏了系统的实现,易用;降低了Client与子系统之间的耦合;仍然可以直接与子系统内部交互;适用性:为复杂系统提供简单接口;为多个子系统提供统一的“门面”,保持子系统的独立变化性;便于构建层次化的系统;3.4.4例DirectX:

Direct3D、DirectInput、DirectMedia3.5装饰模式(DecoratorPattern)改变Dog的Eat实现,怎么办?(两种方式)若只是希望给Dog的Eat扩展一些功能呢?1中的方法会有哪些不足呢?只使用组合的不足:NewDog与Animal不再有父子关系(即使NewDog组合Animal也一样)。Client需要修改。只使用继承的不足:当Eat和Sleep同时变化,有多种组合时,子类数量激增。只能改变单个类的功能,例如这里只能改变Dog的,不能改变Tiger的。不能统一改变全部类型的功能。如不能同时改变Tiger和Dog的Eat。共同使用组合和继承:更一般化的:3.5.2结构3.5.3装饰着模式效果优点:1.保持抽象层上关系的稳定;2.比单独使用组合或继承灵活;3.随时扩展功能或职责;不足:可能产生许多更小的子类;Component类过大时,效率较低,此时可考虑使用策略模式3.5.4例子现在希望扩展所有Shape的Draw功能:即:处理原来正常的绘制外,还要在各自Shape的外边画各自的边框,Circle外边画一个菱形框,Triangle外边画一个矩形框。3.6代理模式当事人律师法院在A对象访问B对象时,为B对象提供一个中介(代理)Proxy,使得A对象不再直接访问B对象,而是直接访问Proxy,由Proxy自行决定是否与B对象交互。这样就可以控制对B对象的访问。例:3.6.2代理模式结构3.6.3代理的种类远程代理(RemoteProxy)隐藏目标对象的位置信息虚拟代理(VirtualProxy)隐藏具体的访问过程及具体实现细节保护代理(ProtectionProxy)保证访问的安全性灵巧(智能)指针(SmartPointer)classSmartPtr

{

public:

SmartPtr(A*p):ptr(p){}

~SmartPtr(){deleteptr;}A*operator->(){returnprt;}

//otheroperations

private:SmartPtr(constSmartPtr&);SmartPtr&operator=(constSmartPtr&);private:

A*ptr;

//otherdata};

main(){SmartPtrpt(newA);pt->f();}对比:main(){A*pt=newA;pt->f();deletept;}3.7享元模式字符图像(例)字符图像是:单行字符串将字符图像加框两个字符图像水平连接两个字符图像垂直连接给出合适的类结构,描述字符图像要方便以后对字符图像的功能扩展第四部分创建型设计模式简单工厂模式(SimpleFactoryPattern)工厂模式(FactoryMethodPattern)抽象工厂模式(AbstractFactoryPattern)单件模式(SingletonPattern)构造器模式(BuilderPattern)原型模式(PrototypePattern)不足使用者与产品紧耦合;产品的创建与使用,采用硬编码;难以适应产品的变化,对开闭原则的支持不好扩展产品子类扩展产品族产品的组装方式变化产品的构建算法4.1简单工厂模式例1例2:Java中DateFormatDateFormat类中的部分代码:publicfinalstaticDateFormatgetInstance();publicfinalstaticDateFormatgetInstance(intstyle);publicfinalstaticDateFormatgetInstance(intstyle,Localloc);例:

Datedate=newDate();StringstrDate=DateFormat.getInstance().Format(date);4.2工厂模式(FactoryMethodPattern)简单工厂方法的不足要求工厂是全能型的不能体现产品的层次性(产品等同化了)扩展产品时,部分支持开闭原则工厂方法模式解决方法工厂方法模式结构工厂方法模式说明目的:定义一个创建产品的接口,而由该接口的子类决定具体实例化哪种产品。将产品的实例化延迟到接口的子类中。优点扩展产品时,完全支持开闭原则;新增子类产品新增产品树用同构的产品树替换原有产品树具有对应的层次结构,Client只通过产品的抽象接口交互,不必明确知道具体的产品不足子类数量可能较多关于实现使用简单工厂方法模式产品结构简单时,特别对于兄弟产品使用工厂方法模式产品结构较复杂时,特别是具有多层次结构的产品树必要时可使用类模版减少子类数量template<classTheProduct>classMyCreator:publicCreator{public:

virtualProduct*CreateProduct();};template<classTheProduct>Product*MyCreator<TheProduct>::CreateProduct(){returnnewTheProduct;}4.3抽象工厂方法具有相同结构层次的产品树可使用工厂方法实现上例中的特性两个产品树,具有相同的结构所有产品,可分为多个系列

(基础英语,专业英语,软件工程三个系列)Client(学生)只能同时使用同一系列中的产品

(学习基础英语,只能使用公外英语教师;

学习基础英语,只能使用专业英语教师;

学习软件工程,只能使用专业课程教师)抽象工厂结构抽象工厂模式说明适应性存在多个产品族(系列),客户只消费其中某一族产品;需要在设计时,体现上述特性优点容易更换产品系列限制客户跨系列消费产品;不足难以添加新种类产品4.5构造器模式Some的多种构建算法Product间的关系构建Some的硬编码分离构建过程与算法例classMazeBuilder{public:

virtualvoidBuildMaze(){}virtualvoidBuildRoom(introom){}virtualvoidBuildDoor(introomFrom,introomTo){}virtualMaze*GetMaze(){return0;}};Maze*Game::CreateMaze(MazeBuilder&builder){ builder.BuildMaze(); builder.BuildRoom(1); builder.BuildRoom(2); builder.BuildDoor(1,2); returnbuilder.GetMaze();};构造器模式效果隐藏了构建的细节和装配过程分离了构造代码和产品表示使用相同的产品,但使用不同的构造器,可以构造不同的复杂对象4.6原型方法原型方法结构说明可以通过一个”注册表”来记录全部实例对象增删注册表,就可以实现动态修改产品改变注册对象,可以相当于新定义一个产品类子类减少Clone操作的实现问题4.4单件模式确保一个类仅有一个实例能够从外部访问它例ClassSingleton{Public:

staticSingleton*Instance();Protected:Singleton();Private:staticSingleton*instance;};Singleton*Singleton::instance=0;Singleton*Singleton::Instance(){if(instance==0)instance=newinstance;returninstance;}说明延迟式单件和饥饿式单件单件类的子类综合举例大富翁游戏:有一个人类玩家和多个电脑玩家在地图上移动,移动后根据所在地的不同,可以买地、盖房、交费等操纵。玩家的钱为0,则出局,剩余的玩家继续玩,直至某个人类玩家成为最终玩家,或者剩余玩家全部为电脑玩家。移动的步数通过掷骰子决定;地图中的道路有多种块组成;房子有多种;游戏的变化模型部分地图的改变地块种类的增加房子种类的增加骰子个数的动态改变玩家种类的细分…视图部分显示风格和素材的变化UI交互的变化引擎的变化…平台间的移植Model与ViewGame包括Model和ViewModel中有多

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论