配色: 字号:
C与设计模式讲义笔记(干货)
2022-03-22 | 阅:  转:  |  分享 
  
C/C++与设计模式基础课程设计模式基础1设计模式编程基础1.1设计模式前言模式在一定环境中解决某一问题的方案,包括三个基本元素--问题
,解决方案和环境。大白话:在一定环境下,用固定套路解决问题。设计模式(Designpattern)是一套被反复使用、多数人知晓
的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。毫无疑问,设计模
式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。学习设计模式的意义
提高职业素养,关注学员在行业内的长期发展。“我眼中的设计模式”把简单的问题复杂化(标准化),把环境中的各个部分进行抽象、归纳、解耦
合。不是多神秘的东西,我们初学者也能学的会。要有信心。学习设计模式的方法对初学者:积累案例,大于背类图。初级开发人员:多思考、多梳
理,归纳总结;尊重事物的认知规律,注意事物临界点的突破。不可浮躁。中级开发人员合适的开发环境,寻找合适的设计模式,解决问题。多应用
对经典组合设计模式的大量、自由的运用。要不断的追求。设计模式的分类GangofFour的“DesignPatterns:E
lementsofResualbelSoftware”书将设计模式归纳为三大类型,共23种。创建型模式:通常和对象的
创建有关,涉及到对象实例化的方式。(共5种模式)结构型模式:描述的是如何组合类和对象以获得更大的结构。(共7种模式)行为型模式
:用来对类或对象怎样交互和怎样分配职责进行描述。(共11种模式)创建型模式用来处理对象的创建过程,主要包含以下5种设计模式:?1
,工厂方法模式(Factory?Method?Pattern)的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。
2,抽象工厂模式(Abstract?Factory?Pattern)的意图是提供一个创建一系列相关或者相互依赖的接口,而无需指定它
们具体的类。3,建造者模式(Builder?Pattern)的意图是将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同
的表示。4,原型模式(Prototype?Pattern)是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。5,单
例模式(Singleton?Pattern)是保证一个类仅有一个实例,并提供一个访问它的全局访问点。?结构型模式用来处理类或者对象
的组合,主要包含以下7种设计模式:6,代理模式(Proxy?Pattern)就是为其他对象提供一种代理以控制对这个对象的访问。7,
装饰者模式(Decorator?Pattern)动态的给一个对象添加一些额外的职责。就增加功能来说,此模式比生成子类更为灵活。?8
,适配器模式(Adapter?Pattern)是将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的
那些类可以一起工作。??9,桥接模式(Bridge?Pattern)是将抽象部分与实际部分分离,使它们都可以独立的变化。10,组合
模式(Composite?Pattern)是将对象组合成树形结构以表示“部分--整体”的层次结构。使得用户对单个对象和组合对象的使
用具有一致性。11,外观模式(Facade?Pattern)是为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这
个接口使得这一子系统更加容易使用。12,享元模式(Flyweight?Pattern)是以共享的方式高效的支持大量的细粒度的对象。
?行为型模式用来对类或对象怎样交互和怎样分配职责进行描述,主要包含以下11种设计模式:13,模板方法模式(Template?Met
hod?Pattern)使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。?14,命令模式(Command?Patt
ern)是将一个请求封装为一个对象,从而使你可用不同的请求对客户端进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。15
,责任链模式(Chain?of?Responsibility?Pattern),在该模式里,很多对象由每一个对象对其下家的引用而连
接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分
配责任。??16,策略模式(Strategy?Pattern)就是准备一组算法,并将每一个算法封装起来,使得它们可以互换。17,中
介者模式(Mediator?Pattern)就是定义一个中介对象来封装系列对象之间的交互。终结者使各个对象不需要显示的相互调用?,
从而使其耦合性松散,而且可以独立的改变他们之间的交互。18,观察者模式(Observer?Pattern)定义对象间的一种一对多的
依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。19,备忘录模式(Memento?Pattern)
是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。20,访问者模式(Visitor?Pattern)就是
表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。21,状态模式(Stat
e?Pattern)就是对象的行为,依赖于它所处的状态。22,解释器模式(Interpreter?Pattern)就是描述了如何为
简单的语言定义一个语法,如何在该语言中表示一个句子,以及如何解释这些句子。?23,迭代器模式(Iterator?Pattern)是
提供了一种方法顺序来访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。1.2设计模式基本原则最终目的:高内聚,低耦合1
)开放封闭原则(OCP,OpenForExtension,ClosedForModificationPrinci
ple)类的改动是通过增加代码进行的,而不是修改源代码。2)单一职责原则(SRP,SingleResponsibilit
yPrinciple)类的职责要单一,对外只提供一种功能,而引起类变化的原因都应该只有一个。3)依赖倒置原则(DIP,Depe
ndenceInversionPrinciple)依赖于抽象(接口),不要依赖具体的实现(类),也就是针对接口编程。4)
接口隔离原则(ISP,InterfaceSegegationPrinciple)不应该强迫客户的程序依赖他们不需要的接口方法
。一个接口应该只提供一种对外功能,不应该把所有操作都封装到一个接口中去。5)里氏替换原则(LSP,LiskovSubs
titutionPrinciple)任何抽象类出现的地方都可以用他的实现类进行替换。实际就是虚拟机制,语言级别实现面向对象功能
。6)优先使用组合而不是继承原则(CARP,Composite/AggregateReusePrinciple)如果使用
继承,会导致父类的任何变换都可能影响到子类的行为。如果使用对象组合,就降低了这种依赖关系。7)迪米特法则(LOD,Lawof
Demeter)一个对象应当对其他对象尽可能少的了解,从而降低各个对象之间的耦合,提高系统的可维护性。例如在一个程序中,各个模块
之间相互调用时,通常会提供一个统一的接口来实现。这样其他模块不需要了解另外一个模块的内部实现细节,这样当一个模块内部的实现发生改变
时,不会影响其他模块的使用。(黑盒原理)案例图开闭原则案例依赖倒转1)2)迪米特法则1)和陌生人说话2)不和陌生人说话3)与依
赖倒转原则结合某人和抽象陌生人说话让某人和陌生人进行解耦合2创建型模式2.1单例模式2.2.1概念单例模式是一种对象创建
型模式,使用单例模式,可以保证为一个类只生成唯一的实例对象。也就是说,在整个程序空间中,该类只存在一个实例对象。GoF对单例模式的
定义是:保证一个类、只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。2.2.2为什么使用单例模式在应用系统开发中,我们
常常有以下需求:-在多个线程之间,比如初始化一次socket资源;比如servlet环境,共享同一个资源或者操作同一个对象-在
整个程序空间使用全局变量,共享资源-大规模系统中,为了性能的考虑,需要节省对象的创建时间等等。因为Singleton模式可以保证
为一个类只生成唯一的实例对象,所以这些情况,Singleton模式就派上用场了。2.2.3实现单例步骤常用步骤构造函数私有化提供一
个全局的静态方法(全局访问点)在类中定义一个静态指针,指向本类的变量的静态变量指针2.2.4饿汉式单例和懒汉式单例懒汉式#in
cludeusingnamespacestd;//懒汉式classSingelton{private
:Singelton(){m_singer=NULL;m_count=0;cout<<"构造函数Singelton.
..do"<er==NULL)//懒汉式:1每次获取实例都要判断2多线程会有问题{m_singer=newSingelto
n;}returnm_singer;}staticvoidprintT(){cout<<"m_count:"<_count<ount;};SingeltonSingelton::m_singer=NULL;//懒汉式并没有创建单例对象int
Singelton::m_count=0;voidmain01_1(){cout<<"演示懒汉式"<Singeltonp1=Singelton::getInstance();//只有在使用的时候,才去创建对象。Singe
ltonp2=Singelton::getInstance();if(p1!=p2){cout<<"不是同一个对
象"<printT();p2->print
T();system("pause");return;}////////////////////////////////////
////////////////////////////////////////俄汉式classSingelton2{priv
ate:Singelton2(){m_singer=NULL;m_count=0;cout<<"构造函数Singelt
on...do"<(m_singer==NULL)//{//m_singer=newSingelton2;//}returnm
_singer;}staticvoidSingelton2::FreeInstance(){if(m_singer!=N
ULL){deletem_singer;m_singer=NULL;m_count=0;}}staticvoidpr
intT(){cout<<"m_count:"<gelton2m_singer;staticintm_count;};Singelton2Singelton2::m_
singer=newSingelton2;//不管你创建不创建实例,均把实例new出来intSingelton2::m_
count=0;voidmain(){cout<<"演示饿汉式"<ingelton2::getInstance();//只有在使用的时候,才去创建对象。Singelton2p2=Sing
elton2::getInstance();if(p1!=p2){cout<<"不是同一个对象"<se{cout<<"是同一个对象"<printT();p2->printT();Singelton2
::FreeInstance();Singelton2::FreeInstance();system("pause");}2.2.
5多线程下的懒汉式单例和饿汉式单例//1"懒汉"模式虽然有优点,但是每次调用GetInstance()静态方法时,必须判断//N
ULL==m_instance,使程序相对开销增大。//2多线程中会导致多个实例的产生,从而导致运行代码不正确以及内存的泄露。
//3提供释放资源的函数讨论:这是因为C++中构造函数并不是线程安全的。C++中的构造函数简单来说分两步:第一步:内存分
配第二步:初始化成员变量由于多线程的关系,可能当我们在分配内存好了以后,还没来得急初始化成员变量,就进行线程切换,另外一个线程
拿到所有权后,由于内存已经分配了,但是变量初始化还没进行,因此打印成员变量的相关值会发生不一致现象。多线程下的懒汉
式问题抛出:#include"stdafx.h"#include"windows.h"#include"winbase.h"
#include#include"iostream"usingnamespacestd;class
Singelton{private:Singelton(){count++;cout<<"Singelton构造函数begin\
n"<防止拷贝构造和赋值操作Singelton(constSingelton&obj){;}Singelton&operato
r=(constSingelton&obj){;}public:staticSingeltongetSingelton
(){//1"懒汉"模式虽然有优点,但是每次调用GetInstance()静态方法时,必须判断//NULL==m_instan
ce,使程序相对开销增大。//2多线程中会导致多个实例的产生,从而导致运行代码不正确以及内存的泄露。//3提供释放资源的函数ret
urnsingle;}staticSingeltonreleaseSingelton(){if(single!=NU
LL)//需要判断{cout<<"释放资源\n"<rnsingle;}voidpirntS()//测试函数{printf("SingeltonprintStestcou
nt:%d\n",count);}private:staticSingeltonsingle;staticintco
unt;};//note静态变量类外初始化SingeltonSingelton::single=newSingelto
n();intSingelton::count=0;int_tmainTTT(intargc,_TCHARargv
[]){Singeltons1=Singelton::getSingelton();Singeltons2=Sin
gelton::getSingelton();if(s1==s2){cout<<"ok....equal"<lse{cout<<"not.equal"<pirntS();Singelton::releaseSinge
lton();cout<<"hello...."<dintthreadfunc2(voidmyIpAdd){intid=GetCurrentThreadId();pr
intf("\nthreadfunc%d\n",id);return1;}voidthreadfunc(voidmy
IpAdd){intid=GetCurrentThreadId();printf("\nthreadfunc%d\n",
id);Singelton::getSingelton()->pirntS();return;}int_tmain(in
targc,_TCHARargv[]){inti=0;DWORDdwThreadId[201],dwThrdP
aram=1;HANDLEhThread[201];intthreadnum=3;for(i=0;idnum;i++){//hThread[i]=(HANDLE)_beginthreadex(NULL,0,&threa
dfunc,NULL,0,&dwThreadId[i]);hThread[i]=(HANDLE)_beginthread
(&threadfunc,0,0);if(hThread[i]==NULL){printf("beginthrea
d%derror!!!\n",i);break;}}//等待所有的子线程都运行完毕后,才执行这个代码for(i=0;
irintf("等待线程结束\n");for(i=0;iead[i]);}Singelton::releaseSingelton();cout<<"hello...."<system("pause");return0;}2.2.6多线程下懒汉式单例的Double-CheckedLocking优化
新建MFC对话框应用程序。方便使用临界区类对象,同步线程//MFCDiagram应用程序#include"stdafx.h
"#include"01单例优化.h"#include"01单例优化Dlg.h"#include"afxdialogex.h
"#include"iostream"usingnamespacestd;//临界区staticCCriticalSect
ioncs;//manpthread_create()classSingleton{private:Singleton()
{TRACE("Singletonbegin\n");Sleep(1000);TRACE("Singletonend\n");
}Singleton(constSingleton&);Singleton&operator=(constSingle
ton&);public:staticvoidprintV(){TRACE("printV..\n");}//请思考;懒汉式
的Double-Check是一个经典问题!为什么需要2次检查“if(pInstance==NULL)”场景:假设有线程1、线
程2、线程3,同时资源竞争。//1)第1个、2个、3个线程执行第一个检查,都有可能进入黄色区域(临界区)//2)若第1个线程进入到
临界区,第2个、第3个线程需要等待//3)第1个线程执行完毕,cs.unlock()后,第2个、第3个线程要竞争执行临界区代码。/
/4)假若第2个线程进入临界区,此时第2个线程需要再次判断if(pInstance==NULL)”,若第一个线程已经创建实例
;第2个线程就不需要再次创建了。保证了单例;//5)同样道理,若第2个线程,cs.unlock()后,第3个线程会竞争执行临界区代
码;此时第3个线程需要再次判断if(pInstance==NULL)。通过检查发现实例已经new出来,就不需要再次创建;保证
了单例。staticSingletonInstantialize(){if(pInstance==NULL)//do
ublecheck{cs.Lock();//只有当pInstance等于null时,才开始使用加锁机制二次检查if(pIn
stance==NULL){pInstance=newSingleton();}cs.Unlock();}return
pInstance;}staticSingletonpInstance;};SingletonSingleton::p
Instance=0;voidCMy01单例优化Dlg::OnBnClickedButton1(){CCriticalSec
tioncs;cs.Lock();cs.Unlock();//TODO:在此添加控件通知处理程序代码}voidthrea
dfunc(voidmyIpAdd){intid=GetCurrentThreadId();TRACE("\nthre
adfunc%d\n",id);Singleton::Instantialize()->printV();//Singelto
n::getSingelton()->pirntS();}voidCMy01单例优化Dlg::OnBnClickedButton
2(){inti=0;DWORDdwThreadId[201],dwThrdParam=1;HANDLEhThr
ead[201];intthreadnum=3;for(i=0;i[i]=(HANDLE)_beginthreadex(NULL,0,&threadfunc,NULL,0,&dwTh
readId[i]);hThread[i]=(HANDLE)_beginthread(&threadfunc,0,0
);if(hThread[i]==NULL){TRACE("beginthread%derror!!!\n",i);
break;}}for(i=0;ii],INFINITE);}TRACE("等待线程结束\n");for(i=0;iloseHandle(hThread[i]);}//Singelton::releaseSingelton();TRACE("
ddddd\n");}2.2.7程序并发机制扩展阅读程序的并发执行往往带来与时间有关的错误,甚至引发灾难性的后果。这需要引入同步机
制。使用多进程与多线程时,有时需要协同两种或多种动作,此过程就称同步(Synchronization)。引入同步机制的第一个原因是
为了控制线程之间的资源同步访问,因为多个线程在共享资源时如果发生访问冲突通常会带来不正确的后果。例如,一个线程正在更新一个结构,同
时另一个线程正试图读取同一个结构。结果,我们将无法得知所读取的数据是新的还是旧的,或者是二者的混合。第二个原因是有时要求确保线程之
间的动作以指定的次序发生,如一个线程需要等待由另外一个线程所引起的事件。为了在多线程程序中解决同步问题,Windows提供了四种主
要的同步对象,每种对象相对于线程有两种状态——信号状态(signalstate)和非信号状态(nonsignalstate)。当
相关联的同步对象处于信号状态时,线程可以执行(访问共享资源),反之必须等待。这四种同步对象是:(1)事件对象(Event)。事件对
象作为标志在线程间传递信号。一个或多个线程可等待一个事件对象,当指定的事件发生时,事件对象通知等待线程可以开始执行。它有两种类型:
自动重置(auto-reset)事件和手动重置(manual-reset)事件。(2)临界区(CriticalSection)。
临界区对象通过提供一个进程内所有线程必须共享的对象来控制线程。只有拥有那个对象的线程可以访问保护资源。在另一个线程可以访问该资源之
前,前一个线程必须释放临界区对象,以便新的线程可以索取对象的访问权。(3)互斥量(MutexSemaphore)。互斥量的工作方
式非常类似于临界区,只是互斥量不仅保护一个进程内为多个线程使用的共享资源,而且还可以保护系统中两个或多个进程之间的的共享资源。(4
)信号量(Semaphore)。信号量可以允许一个或有限个线程访问共享资源。它是通过计数器来实现的,初始化时赋予计数器以可用资源数
,当将信号量提供给一个线程时,计数器的值减1,当一个线程释放它时,计数器值加1。当计数器值小于等于0时,相应线程必须等待。信号量是
Windows98同步系统的核心。从本质上讲,互斥量是信号量的一种特殊形式。Windows/NT还提供了另外一种Windows95
没有的同步对象:可等待定时器(WaitableTimer)。它可以封锁线程的执行,直到到达某一具体时间。这可以用于后台任务。同步
问题是多线程编程中最复杂的问题,后面的linux系统编程中,还会有更深入的介绍。2.2.8总结在很多人印象中,单例模式可能是23
个设计模式中最简单的一个。如果不考虑多线程,的确如此,但是一旦要在多线程中运用,那么从我们的教程中可以了解到,它涉及到很多编译
器,多线程,C++语言标准等方面的内容。本专题参考的资料如下:1、C++Primer(StanleyB.Lippman),
主要参考的是模板静态变量的初始化以及实例化。2、MSDN,有关线程同步interlocked相关的知识。3、Effectiv
eC++04条款(ScottMeyers)Non-Local-Static对象初始化顺序以及Meyers单例模式的实现。
4、Double-CheckedLocking,Threads,CompilerOptimizations,andMore
(ScottMeyers),解释了由于编译器的优化,导致auto_ptr.reset函数不安全,shared_ptr有类似情
况。我们避免使用reset函数。5、C++全局和静态变量初始化顺序的研究(CSDN)。6、四人帮的经典之作:设计模式7、wi
ndows核心编程(JeffreyRichter)2.2简单工厂模式2.2.1什么是简单工厂模式简单工厂模式属于类的创建型
模式,又叫做静态工厂方法模式。通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。2.2.2模式中包含的角
色及其职责1.工厂(Creator)角色简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的
产品对象。2.抽象(Product)角色简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。3.具体产品(Co
ncreteProduct)角色简单工厂模式所创建的具体实例对象//依赖:一个类的对象当另外一个类的函数参数或者是返回值
3简单工厂模式的优缺点在这个模式中,工厂类是整个模式的关键所在。它包含必要的判断逻辑,能够根据外界给定的信息,决定究竟应该创建哪
个具体类的对象。用户在使用时可以直接根据工厂类去创建所需的实例,而无需了解这些对象是如何创建以及如何组织的。有利于整个软件体系结构
的优化。不难发现,简单工厂模式的缺点也正体现在其工厂类上,由于工厂类集中了所有实例的创建逻辑,所以“高内聚”方面做的并不好。另外,
当系统中的具体产品类不断增多时,可能会出现要求工厂类也要做相应的修改,扩展性并不很好。2.2.3案例include"iost
ream"usingnamespacestd;//思想:核心思想是用一个工厂,来根据输入的条件产生不同的类,然后根据不同类的
virtual函数得到不同的结果。//元素分析://抽象产品类:水果类//具体的水果了:香蕉类、苹果类、梨子//优点适用于不同情
况创建不同的类时//缺点客户端必须要知道基类和工厂类,耦合性差增加一个产品,需要修改工厂类classFruit{public
:virtualvoidgetFruit()=0;protected:private:};classBanana:p
ublicFruit{public:virtualvoidgetFruit(){cout<<"香蕉"<ected:private:};classPear:publicFruit{public:virtualvoidget
Fruit(){cout<<"梨子"<ic:staticFruitCreate(charname){Fruittmp=NULL;if(strcmp(
name,"pear")==0){tmp=newPear();}elseif(strcmp(name,"bana
na")==0){tmp=newBanana();}else{returnNULL;}returntmp;}prot
ected:private:};voidmain41(){Fruitpear=Factory::Create("pea
r");if(pear==NULL){cout<<"创建pear失败\n";}pear->getFruit();Fruit
banana=Factory::Create("banana");banana->getFruit();system("p
ause");}2.2.4练习主要用于创建对象。新添加类时,不会影响以前的系统代码。核心思想是用一个工厂来根据输入的条件产生不同的
类,然后根据不同类的virtual函数得到不同的结果。GOOD:适用于不同情况创建不同的类时BUG:客户端必须要知道基类和工厂类
,耦合性差(工厂类与基类为关联关系)#include"iostream"usingnamespacestd;//需求://模
拟四则运算;//用操作符工厂类生产操作符(加减乘除),进行结果运算//运算符抽象类COperation//加减乘除具体的类(注
意含有2个操作数)//工厂类CCalculatorFactory//核心思想用一个工厂来根据输入的条件产生不同的类,然后根据不
同类的virtual函数得到不同的结果classCOperation{public:intfirst;intsecond;p
ublic:virtualdoubleGetResult()=0;private:};classAddOperation
:publicCOperation{public:doubleGetResult(){returnfirst+sec
ond;}private:};classSubOperation:publicCOperation{public:doub
leGetResult(){returnfirst-second;}private:};classCCalculator
Factory{public:staticCOperationCreateOperation(charcOperator){
COperationtmp=NULL;switch(cOperator){case''+'':tmp=newAddO
peration();break;case''-'':tmp=newSubOperation();break;default:
tmp=NULL;}returntmp;}};voidmain(){COperationop1=CCalculat
orFactory::CreateOperation(''+'');op1->first=10;op1->second=20;
cout<GetResult()<::CreateOperation(''-'');op2->first=10;op2->second=20;cout<->GetResult()<3.1概念工厂方法模式同样属于类的创建型模式又被称为多态工厂模式。工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际
创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步
抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。2.3.2类图角色和职责抽象工厂(Creator
)角色工厂方法模式的核心,任何工厂类都必须实现这个接口。具体工厂(ConcreteCreator)角色具体工厂类是抽象工厂的
一个实现,负责实例化产品对象。抽象(Product)角色工厂方法模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。具
体产品(ConcreteProduct)角色工厂方法模式所创建的具体实例对象2.3.3工厂方法模式和简单工厂模式比较工厂方法
模式与简单工厂模式在结构上的不同不是很明显。工厂方法类的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。工厂方法模式
之所以有一个别名叫多态性工厂模式是因为具体工厂类都有共同的接口,或者有共同的抽象父类。当系统扩展需要添加新的产品对象时,仅仅需要添
加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了“开放-封闭”原则。而简单工厂
模式在添加新产品对象后不得不修改工厂方法,扩展性不好。工厂方法模式退化后可以演变成简单工厂模式。“开放-封闭”通过添加代码的方式
,不是通过修改代码的方式完成功能的增强。#include"iostream"usingnamespacestd;class
Fruit{public:virtualvoidsayname(){cout<<"fruit\n";}};classFrui
tFactory{public:virtualFruitgetFruit(){returnnewFruit();}};/
/香蕉classBanana:publicFruit{public:virtualvoidsayname(){cout
<<"Banana\n"<actory{public:virtualFruitgetFruit(){returnnewBanana;}};//苹果
classApple:publicFruit{public:virtualvoidsayname(){cout<<"A
pple\n"<{public:virtualFruitgetFruit(){returnnewApple;}};voidmain()
{FruitFactoryff=NULL;Fruitfruit=NULL;//1ff=newBanana
Factory();fruit=ff->getFruit();fruit->sayname();deletefruit;de
leteff;//2苹果ff=newAppleFactory();fruit=ff->getFruit();fruit
->sayname();deletefruit;deleteff;cout<<"hello....\n";system("pa
use");}2.4抽象工厂2.4.1概念抽象工厂模式是所有形态的工厂模式中最为抽象和最其一般性的。抽象工厂模式可以向客户端提供
一个接口,使得客户端在不必指定产品的具体类型的情况下,能够创建多个产品族的产品对象。2.4.2产品族和产品等级结构备注1:工厂模式
:要么生产香蕉、要么生产苹果、要么生产西红柿;但是不能同时生产一个产品组。抽象工厂:能同时生产一个产品族。===》抽象工厂存在原因
解释:具体工厂在开闭原则下,能生产香蕉/苹果/梨子;(产品等级结构)抽象工厂:在开闭原则下,能生产:南方香蕉/苹果/梨子(产
品族)北方香蕉/苹果/梨子重要区别:工厂模式只能生产一个产品。(要么香蕉、要么苹果)抽象工厂可以一下生产一个产品族(里面有很多产品
组成)2.4.3模式中包含的角色及其职责抽象工厂(Creator)角色抽象工厂模式的核心,包含对多个产品结构的声明,任何工厂类都
必须实现这个接口。具体工厂(ConcreteCreator)角色具体工厂类是抽象工厂的一个实现,负责实例化某个产品族中的产品
对象。抽象(Product)角色抽象模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。具体产品(ConcreteP
roduct)角色抽象模式所创建的具体实例对象2.4.4案例classFruit{public:virtualvoidsa
yname(){cout<<"fruit\n";}};classFruitFactory{public:virtualFrui
tgetApple(){returnnewFruit();}virtualFruitgetBanana(){retu
rnnewFruit();}};//南方香蕉classSouthBanana:publicFruit{public:v
irtualvoidsayname(){cout<<"SouthBanana\n"<sSouthApple:publicFruit{public:virtualvoidsayname(){cout<<"
SouthApple\n"<ublic:virtualvoidsayname(){cout<<"NorthBanana\n"<方苹果classNorthApple:publicFruit{public:virtualvoidsayname(){
cout<<"NorthApple\n"<FruitFactory{public:virtualFruitgetApple(){returnnewSouthAp
ple();}virtualFruitgetBanana(){returnnewSouthBanana();}};cla
ssNorthFruitFactory:publicFruitFactory{public:virtualFruit
getApple(){returnnewNorthApple();}virtualFruitgetBanana(){re
turnnewNorthBanana();}};voidmain(){FruitFactoryff=NULL;F
ruitfruit=NULL;ff=newSourthFruitFactory();fruit=ff->getA
pple();fruit->sayname();fruit=ff->getBanana();fruit->sayname();
deletefruit;deleteff;ff=newNorthFruitFactory();fruit=ff->g
etApple();fruit->sayname();fruit=ff->getBanana();fruit->sayname
();deletefruit;deleteff;cout<<"hello....\n";system("pause");}2.
5建造者模式概念Builder模式也叫建造者模式或者生成器模式,是由GoF提出的23种设计模式中的一种。Builder模式是一种
对象创建型模式之一,用来隐藏复合对象的创建过程,它把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态地创建具有复合属性的
对象。对象的创建:Builder模式是为对象的创建而设计的模式-创建的是一个复合对象:被创建的对象为一个具有复合属性的复合对象-
关注对象创建的各部分的创建过程:不同的工厂(这里指builder生成器)对产品属性有不同的创建方法角色和职责1)Builder
:为创建产品各个部分,统一抽象接口。2)ConcreteBuilder:具体的创建产品的各个部分,部分A,部分B,部分C。3)
Director:构造一个使用Builder接口的对象。4)Product:表示被构造的复杂对象。ConcreteBuilde
r创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。适用情况:一个对象的构建比较复
杂,将一个对象的构建(?)和对象的表示(?)进行分离。创建者模式和工厂模式的区别Factory模式中:1、有一个抽象的工厂。2、实
现一个具体的工厂---汽车工厂。3、工厂生产汽车A,得到汽车产品A。4、工厂生产汽车B,得到汽车产品B。这样做,实现了购买者和
生产线的隔离。强调的是结果。Builder模式:1、引擎工厂生产引擎产品,得到汽车部件A。2、轮胎工厂生产轮子产品,得到汽车部
件B。3、底盘工厂生产车身产品,得到汽车部件C。4、将这些部件放到一起,形成刚好能够组装成一辆汽车的整体。5、将这个整体送到汽车组
装工厂,得到一个汽车产品。这样做,目的是为了实现复杂对象生产线和其部件的解耦。强调的是过程两者的区别在于:Factory模式不考虑
对象的组装过程,而直接生成一个我想要的对象。Builder模式先一个个的创建对象的每一个部件,再统一组装成一个对象。Factory
模式所解决的问题是,工厂生产产品。而Builder模式所解决的问题是工厂控制产品生成器组装各个部件的过程,然后从产品生成器中得到产
品。Builder模式不是很常用。模式本身就是一种思想。知道了就可以了。设计模式就是一种思想。学习一个模式,花上一两个小时把此模
式的意思理解了,就够了。其精华的所在会在以后工作的设计中逐渐体现出来。案例关键字:建公寓工程队FlatBuild
别墅工程队VillaBuild设计者Director#includeusingnamespaces
td;#include"string"classHouse{public:voidsetFloor(stringfloor
){this->m_floor=floor;}voidsetWall(stringwall){this->m_wall=
wall;}voidsetDoor(stringdoor){this->m_door=door;}//stringge
tFloor(){returnm_floor;}stringsetWall(){returnm_wall;}string
setDoor(){returnm_door;}protected:private:stringm_floor;stringm_
wall;stringm_door;};classBuilder{public:virtualvoidmakeFloor()
=0;virtualvoidmakeWall()=0;virtualvoidmakeDoor()=0;vir
tualHouseGetHouse()=0;};//公寓classFlatBuild:publicBuilder
{public:FlatBuild(){pHouse=newHouse;}virtualvoidmakeFloor(){
pHouse->setFloor("flatDoor");}virtualvoidmakeWall(){pHouse->se
tWall("flatWall");}virtualvoidmakeDoor(){pHouse->setDoor("flat
Door");}virtualHouseGetHouse(){returnpHouse;}private:House
pHouse;};//别墅classVillaBuild:publicBuilder{public:VillaBuild(
){pHouse=newHouse;}virtualvoidmakeFloor(){pHouse->setFloor("
villafloor");}virtualvoidmakeWall(){pHouse->setWall("villaWal
l");}virtualvoidmakeDoor(){pHouse->setDoor("villaDoor");}virtu
alHouseGetHouse(){returnpHouse;}private:HousepHouse;};class
Director{public:voidConstruct(Builderbuilder){builder->makeFl
oor();builder->makeWall();builder->makeDoor();}protected:private:
};voidmain(){//客户直接造房子HousepHose=newHouse;pHose->setDoor("w
bm门");pHose->setFloor("wbmFloor");pHose->setWall("wbmWall");delet
epHose;///工程队直接造房子Builderbuilder=newFlatBuild;builder->m
akeFloor();builder->makeWall();builder->makeDoor();///指挥者(设计师)指挥
工程队和建房子Directordirector=newDirector;//建公寓Builderbuilder
=newFlatBuild;director->Construct(builder);//设计师指挥工程队干活Hous
ehouse=builder->GetHouse();cout<getFloor()<deletehouse;deletebuilder;//建别墅builder=newVillaBuild;directo
r->Construct(builder);//设计师指挥工程队干活house=builder->GetHouse();
cout<getFloor()<etedirector;system("pause");return;}2.6原型模式prototype概念Prototype
模式是一种对象创建型模式,它采取复制原型对象的方法来创建对象的实例。使用Prototype模式创建的实例,具有与原型一样的数据。1
)由原型对象自身创建目标对象。也就是说,对象创建这一动作发自原型对象本身。2)目标对象是原型对象的一个克隆。也就是说,通过Prot
otype模式创建的对象,不仅仅与原型对象具有相同的结构,还与原型对象具有相同的值。3)根据对象克隆深度层次的不同,有浅度克隆与深
度克隆。角色和职责原型模式主要面对的问题是:“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他
们却拥有比较稳定一致的接口。适用情况:一个复杂对象,具有自我复制功能,统一一套接口。案例classPerson{public:v
irtualPersonClone()=0;virtualvoidprintT()=0;};classJava
Programmer:publicPerson{public:JavaProgrammer(){this->m_name=
"";this->m_age=0;m_resume=NULL;}JavaProgrammer(stringname,
intage){this->m_name=name;this->m_age=age;m_resume=NULL;}~
JavaProgrammer(){if(m_resume!=NULL){free(m_resume);m_resume=N
ULL;}}virtualPersonClone(){JavaProgrammerp=newJavaProgram
mer;p=this;returnp;}voidsetResume(charresume){m_resume=
newchar[strlen(resume)+1];strcpy(m_resume,resume);}virtualvo
idprintT(){cout<<"m_name:"<age<ected:private:stringm_name;intm_age;charm_resume;};voidmain(){J
avaProgrammerjavaperson1("张三",30);javaperson1.setResume("我是java
程序员");Personp2=javaperson1.Clone();//对象具有自我复制功能注意深拷贝和浅拷贝问题
p2->printT();deletep2;cout<<"hello..."<urn;}3结构型模式3.1代理模式概念Proxy模式又叫做代理模式,是构造型的设计模式之一,它可以为其他对象提供一种代理(Pr
oxy)以控制对这个对象的访问。所谓代理,是指具有与代理元(被代理的对象)具有相同的接口的类,客户端必须通过代理与被代理的目标类交
互,而代理一般在交互的过程中(交互前后),进行某些特别的处理。类图角色和职责subject(抽象主题角色):真实主题与代理主题的共
同接口。RealSubject(真实主题角色):?定义了代理角色所代表的真实对象。Proxy(代理主题角色):?含有对真实主题角
色的引用,代理角色通常在将客户端调用传递给真是主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象。适合于:为其他对象提供一
种代理以控制对这个对象的访问。提示:a中包含b类;a、b类实现协议类protocol理论模板理论模型提示:a中包含b类;a、b类
实现协议类protocol#include#includeusingnamespace
std;//定义接口classInterface{public:virtualvoidRequest()=0;};//真实类
classRealClass:publicInterface{public:virtualvoidRequest(){
cout<<"真实的请求"<rivate:RealClassm_realClass;public:virtualvoidRequest(){m_re
alClass=newRealClass();m_realClass->Request();deletem_realClas
s;}};客户端:intmain(){ProxyClasstest=newProxyClass();test->Reque
st();return0;}案例案例2cocos2d-x中应用程序代理类出版社被代理对象,要卖书淘宝、当当网(网上书店),代理
对象客户端通过当当网进行买书。#includeusingnamespacestd;/subject(抽
象主题角色):真实主题与代理主题的共同接口。RealSubject(真实主题角色):定义了代理角色所代表的真实对象。Proxy(
代理主题角色):含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真是主题对象之前或者之后执行某些操作,而不是单纯返回真实
的对象。提示:a中包含b类;a、b类实现协议类protocol/classSubject{public:virtualv
oidSaleBook()=0;protected:private:};classRealSubject:publi
cSubject{public:virtualvoidSaleBook(){cout<<"实体店买书....\n";}p
rotected:private:};classProxyTaoBao:publicSubject{public:vir
tualvoidSaleBook(){//Double11();RealSubjectrs;rs.SaleBook();Do
uble11();}voidDouble11(){cout<<"Double11打折半价"<cted:private:};classProxyTaoBao2:publicSubject{public:voidS
etRealSubject(RealSubjectrs){m_s=rs;}virtualvoidSaleBook(){
Double11();m_s->SaleBook();}voidDouble11(){cout<<"Double11打折
半价"<roxyTaoBaoptb=newProxyTaoBao;ptb->SaleBook();deleteptb;retu
rn;}#include"iostream"usingnamespacestd;//a包含了一个类b,类b实现了某一个协议
(一套接口)classAppProtocol{public:virtualintApplicationDidFinsh()
=0;protected:private:};//协议实现类classAppDelegate:publicAppProt
ocol{public:AppDelegate(){;}virtualintApplicationDidFinsh()//
cocos2dx函数的入口点{cout<<"ApplicationDidFinshdo...\n";return0;}};//
Application是代理类,在代理类中包含一个真正的实体类classApplication{public:Applicati
on(){ap=NULL;}public:voidrun(){ap=newAppDelegate();ap->Appl
icationDidFinsh();deleteap;}protected:private:AppDelegateap;};
//好处:main函数不需要修改了。只需要修改协议实现类voidmain31(){Applicationapp=new
Application();app->run();if(app==NULL){free(app);}cout<<"hello
..."<行升级打怪3.2装饰模式概念装饰(Decorator)模式又叫做包装模式。通过一种对客户端透明的方式来扩展对象的功能,是继承
关系的一个替换方案。装饰模式就是把要添加的附加功能分别放在单独的类中,并让这个类包含它要装饰的对象,当需要执行时,客户端就可以有选
择地、按顺序地使用装饰功能包装对象。类图角色和职责适用于:装饰者模式(Decorator?Pattern)动态的给一个对象添加一些
额外的职责。就增加功能来说,此模式比生成子类更为灵活。案例#includeusingnamespaces
td;classCar{public:virtualvoidshow()=0;protected:private:};c
lassRunCar:publicCar{public:voidrun(){cout<<"可以跑"<}virtualvoidshow(){run();}protected:private:};classSwimCarDire
ctor:publicCar{public:SwimCarDirector(Carp){m_p=p;}voidsw
im(){cout<<"可以游"<show();swim(
);}private:Carm_p;};classFlyCarDirector:publicCar{public:Fl
yCarDirector(Carp){m_p=p;}voidfly(){cout<<"可以飞"<irtualvoidshow(){m_p->show();fly();}private:Carm_p;};voidmai
n(){Carruncar=NULL;runcar=newRunCar;runcar->show();cout<<
"车开始装饰swim"<runcar);swimCar->show();cout<<"车开始装饰fly"<lyCar=newFlyCarDirector(swimCar);flyCar->show();deleteflyCar;
deleteswimCar;deleteruncar;return;}3.3适配器模式adapter概念Adapter模式
也叫适配器模式,是构造型模式之一,通过Adapter模式可以改变已有类(或外部类)的接口形式。角色和职责适用于:是将一个类的接口转
换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。案例#includeu
singnamespacestd;classCurrent18v{public:voiduse18vCurrent(){c
out<<"使用18v的交流电"<{public:voiduse220vCurrent(){cout<<"使用220v的交流电"<cted:private:};classAdapter:publicCurrent18v{public:Adapter(C
urrent220vp220v){m_p220v=p220v;}voiduse18vCurrent(){cout<<
"adapter中使用电流"<use220vCurrent();}protected:priva
te:Current220vm_p220v;};voidmain(){Current220vp220v=newCu
rrent220v;Adapterpadapter=newAdapter(p220v);padapter->use18v
Current();deletep220v;deletepadapter;system("pause");return;}练
习足球比赛中,中场球员可进攻和防守,教练通过翻译告诉中场球员,要进攻。思路:Player,抽象的球员(Attack、Defen
se)classTransLater:publicPlayer适配器classCenter:publicPlay
er被适配的对象3.4组合模式概念Composite模式也叫组合模式,是构造型的设计模式之一。通过递归手段来构造树形的对象结构,
并可以通过一个对象来访问整个对象树。角色和职责Component(树形结构的节点抽象)-为所有的对象定义统一的接口(公共属性,
行为等的定义)-提供管理子节点对象的接口方法-[可选]提供管理父节点对象的接口方法Leaf(树形结构的叶节点)Compone
nt的实现子类Composite(树形结构的枝节点)Component的实现子类适用于:单个对象和组合对象的使用具有一致性。将对象
组合成树形结构以表示“部分--整体”案例#includeusingnamespacestd;#inclu
de"list"#include"string"//classIFile{public:virtualvoiddispl
ay()=0;virtualintadd(IFileifile)=0;virtualintremove(IFi
leifile)=0;virtuallistgetChild()=0;protected:pr
ivate:};classFile:publicIFile{public:File(stringname){m_list
=NULL;m_name="";m_name=name;}~File(){if(m_list!=NULL){de
letem_list;}}virtualvoiddisplay(){cout<ualintadd(IFileifile){return-1;}virtualintremove(IFileif
ile){return-1;}virtuallistgetChild(){returnNULL;}p
rivate:listm_list;stringm_name;};classFolder:public
IFile{public:Folder(stringname){m_name=name;m_list=newlist
;}~Folder(){if(m_list==NULL){deletem_list;}}virtual
voiddisplay(){cout<le){m_list->push_back(ifile);return0;}virtualintremove(IFile
ifile){m_list->remove(ifile);return0;}virtuallistget
Child(){returnm_list;}private:listm_list;stringm_nam
e;};voidshowTree(IFileifile,intlevel){listl=NUL
L;inti=0;for(i=0;idisplay(
);l=ifile->getChild();if(l!=NULL){for(list::iterat
orit=l->begin();it!=l->end();it++){if((it)->getChild()==N
ULL){for(i=0;i<=level;i++)//注意<={printf("\t");}(it)->displ
ay();}else{showTree((it),level+1);}}}}voidmain(){Folderroo
t=newFolder("C:");Folderdir1=newFolder("111dir");Filetx
t1=newFile("aaa.txt");Folderdir12=newFolder("222dir");//d
ir12->display();Filetxt12=newFile("222.txt");//txt12->displa
y();root->display();root->add(dir1);root->add(txt1);dir1->add(dir
12);dir1->add(txt12);/listl=dir1->getChild();for(l
ist::iteratorit=l->begin();it!=l->end();it++){(it)->
display();}///开发一个递归函数现在根结点下的所有子结点cout<<"测试递归函数"<Tree(root,0);deletetxt12;deletedir12;deletedir1;deletetxt1;d
eleteroot;cout<<"hello..."<式bridge概念Bridge模式又叫做桥接模式,是构造型的设计模式之一。Bridge模式基于类的最小设计原则,通过使用封装,聚
合以及继承等行为来让不同的类承担不同的责任。它的主要特点是把抽象(abstraction)与行为实现(implementation
)分离开来,从而可以保持各部分的独立性以及应对它们的功能扩展。角色和职责ClientBridge模式的使用者Abstractio
n抽象类接口(接口或抽象类)维护对行为实现(Implementor)的引用RefinedAbstractionAbstrac
tion子类Implementor行为实现类接口(Abstraction接口定义了基于Implementor接口的更高层次的操
作)ConcreteImplementorImplementor子类?适用于:桥接模式(Bridge?Pattern)是将抽象部分
与实现部分分离(解耦合),使它们都可以独立的变化。车安装发动机;不同型号的车,安装不同型号的发动机图形填颜色不同
形状的图形,填充上不同的颜色将“车安装发动机”这个抽象和实现进行分离;两个名字就设计两个类;将“图形填颜色”这个抽
象和实现进行分离,两个名字,就设计两个类案例#includeusingnamespacestd;c
lassMyCar1{public:virtualvoidinstallEngine()=0;};classBMW5
:publicMyCar1{public:virtualvoidinstallEngine(){cout<<"BMW5
3500CC"<dinstallEngine(){cout<<"BMW64000CC"<publicMyCar1{public:virtualvoidinstallEngine(){cout<<"Jeep1
11100CC"<voidinstallEngine(){cout<<"Jeep121200CC"<同型号,安装不同类型的发动机,会引起子类的泛滥//问题引出voidmain1601(){Jeep12j12=newJe
ep12;j12->installEngine();deletej12;return;}classMyCar2{public
:virtualvoidinstallEngine3500()=0;virtualvoidinstallEngine4
000()=0;virtualvoidinstallEngine1100()=0;virtualvoidinsta
llEngine1200()=0;};classBMW:publicMyCar2{public:virtualvoi
dinstallEngine3500(){cout<<"3500CC"<allEngine4000(){cout<<"4000CC"<ine1100(){cout<<"1100CC"<00(){cout<<"1200CC"<MWbmw5=newBMW;bmw5->installEngine3500();}//需要把“安装发动机”这个事,做很好
的分解;把抽象和行为实现分开//发动机是一个名次,专门抽象成一个类;类中含有一个成员函数,安装发动机classEngine
{public:virtualvoidinstallEngine()=0;};classEngine4000:pub
licEngine{public:virtualvoidinstallEngine(){cout<<"安装发动机Eng
ine4000"<alvoidinstallEngine(){cout<<"安装发动机Engine3500"<assCar{public:Car(Enginepengine){m_engine=pengine;}virtualv
oidinstallEngine()=0;protected:Enginem_engine;};classBMW7:
publicCar{public:BMW7(Enginep):Car(p){}//注意车的安装和发动机的安装不同
之处virtualvoidinstallEngine(){cout<<"BMW7";m_engine->instal
lEngine();}protected:private:};voidmain163(){Engine4000e4000=
newEngine4000;BMW7bmw7=newBMW7(e4000);bmw7->installEngine(
);deletebmw7;deletee4000;}voidmain(){//main1601();//main1602()
;main163();system("pause");}练习在上述案例场景之中,让jeep11车,安装上1100CC发动机。方法:
添加Jeep11类,添加Engine1100CC发动机类,在main函数中编写测试案例,体会设计模式的开闭原则。抽象一个图形Abs
tractShape,含有操作draw(),可以画圆形、正方形抽象一个颜色类color,含有getColor():string让A
bstractShape持有一个color的引用。形成桥接模式。创建类classCircle:publicAbstrac
tShapeClassSquare:publiceAbstractShape创建类ClassRed:publicc
olorClassGreen:publiccolor测试:用红色画正方形Voidmain(){Colorcolo
r=newRed();AbstractShapeshap=newSquare(color);shap.draw()
;}3.6外观模式fa?ade概念Facade模式也叫外观模式,是由GoF提出的23种设计模式中的一种。Facade模式为一组具
有类似功能的类群,比如类库,子系统等等,提供一个一致的简单的界面。这个一致的简单的界面被称作facade。角色和职责Fa?ade为
调用方,定义简单的调用接口。Clients?调用者。通过Facade接口调用提供某功能的内部类群。Packages?功能提供者。
指提供功能的类群(模块或子系统)适用于:为子系统中统一一套接口,让子系统更加容易使用。案例#includeu
singnamespacestd;classSystemA{public:voiddoThing(){cout<<"s
ystemAdo...."<t<<"systemAdo...."<g(){cout<<"systemAdo...."<e(){a=newSystemA;b=newSystemB;c=newSystemC;}~Facade(){de
letea;deleteb;deletec;}voiddoThing(){a->doThing();b->doThing(
);c->doThing();}protected:private:SystemAa;SystemBb;SystemC
c;};voidmain1414(){/SystemAa=newSystemA;SystemBb=newS
ystemB;SystemCc=newSystemC;a->doThing();b->doThing();c->doTh
ing();deletea;deleteb;deletec;/Facadef=newFacade;f->doTh
ing();deletef;cout<<"hello..."<案例基金(股票、外汇、期货、国债)3.7享元模式flyweight概念Flyweight模式也叫享元模式,是构造型模式之一,它通过
与其他类似对象共享数据来减小内存占用。角色和职责抽象享元角色:所有具体享元类的父类,规定一些需要实现的公共接口。具体享元角色:?抽
象享元角色的具体实现类,并实现了抽象享元角色规定的方法。享元工厂角色:??负责创建和管理享元角色。使用场景:是以共享的方式,高效的
支持大量的细粒度的对象。案例#includeusingnamespacestd;#include"st
ring"#include"map"classPerson{public:Person(stringname,intag
e,intsex){this->name=name;this->age=age;this->sex=sex;}st
ringgetName(){returnname;}intgetAge(){returnage;}intgetSex()
{returnsex;}protected:stringname;intage;intsex;//1男2女};classT
eacher:publicPerson{public:Teacher(stringid,stringname,int
age,intsex):Person(name,age,sex){this->id=id;}stringget
Id(){returnid;}voidprintT(){cout<<"id:"<:"<<Factory(){m_tpool.empty();}~TeacherFactory(){//内存管理永远是c++程序员的痛wh
ile(!m_tpool.empty())//在工厂中创建老师结点,在工厂中销毁老师结点{Teachertmp=NUL
L;map::iteratorit=m_tpool.begin();tmp=it-
>second;m_tpool.erase(it);deletetmp;}}//通过Teacher的pool,来存放老师结点,在
TeacherFactory中创建老师、销毁老师TeachergetTeacher(stringtid){stringnam
e;intage;intsex;Teachertmp=NULL;map::iterat
orit=m_tpool.find(tid);if(it==m_tpool.end()){cout<<"id为:
"<";cin>>name;cout<<"请输入老师年龄:";cin>>age;cout<<"请输入老师性别1男2
女:";cin>>sex;tmp=newTeacher(tid,name,age,sex);m_tpool.ins
ert(pair(tid,tmp));}else{tmp=(it->second);}r
eturntmp;}private:mapm_tpool;};voidmain(){/
Teachert1=newTeacher("001","小李",30,1);Teachert2=new
Teacher("002","小张",30,1);Teachert3=newTeacher("001","小李"
,30,1);Teachert4=newTeacher("004","小吴",30,1);//cout<<
"t1t3的工号一样,但是也不是同一个人"<letet4;/TeacherFactoryteacherFactory=newTeacherFactory;Tea
chert1=teacherFactory->getTeacher("001");t1->printT();Teacher
t2=teacherFactory->getTeacher("001");t2->printT();deletetea
cherFactory;system("pause");return;}4行为型模式4.1模板模式template概念Templ
ateMethod模式也叫模板方法模式,是行为模式之一,它把具有特定步骤算法中的某些必要的处理委让给抽象方法,通过子类继承对抽象
方法的不同实现改变整个算法的行为。应用场景TemplateMethod模式一般应用在具有以下条件的应用中:-具有统一的操作步骤
或操作过程-具有不同的操作细节-存在多个具有同样操作步骤的应用场景,但某些具体的操作细节却各不相同总结:在抽象类中统一操作步骤
,并规定好接口;让子类实现接口。这样可以把各个具体的子类和操作步骤接耦合角色和职责AbstractClass:抽象类的父类Conc
reteClass:具体的实现子类templateMethod():模板方法method1()与method2():具体步骤方法
案例#includeusingnamespacestd;classMakeCar{public:vi
rtualvoidmakeHead()=0;virtualvoidmakeBody()=0;virtualvoi
dmakeTail()=0;public://把一组行为变成一个模板voidmake(){makeHead();
makeBody();makeTail();}protected:private:};classMakeBus:public
MakeCar{public:virtualvoidmakeHead(){cout<<"bus组装车头"<dl;}virtualvoidmakeBody(){cout<<"bus组装车身"<voidmakeTail(){cout<<"bus组装车尾"<classMakeJeep:publicMakeCar{public:virtualvoidmakeHead(){co
ut<<"Jeep组装车头"<组装车身"<endl;}protected:private:};voidmain(){MakeCarbus=newMakeBus;
//bus->makeHead();//bus->makeBody();//bus->makeTail();bus->make()
;MakeCarjeep=newMakeJeep;//jeep->makeHead();//jeep->makeBody
();//jeep->makeTail();jeep->make();deletebus;deletejeep;cout<<"
hello..."<式也叫命令模式,是行为设计模式的一种。Command模式通过被称为Command的类封装了对目标对象的调用行为以及调用参数。在面
向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建目标对象实例;设置调用参数;调用目标对象的方法。但在有些情
况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门的类称作command类。整个调用过程比较繁杂,或者存在多处这种调
用。这时,使用Command类对该调用加以封装,便于功能的再利用。-调用前后需要对调用参数进行某些处理。调用前后需要进行某些额外处
理,比如日志,缓存,记录历史操作等。角色和职责CommandCommand命令的抽象类。ConcreteCommand?Comm
and的具体实现类。Receiver?需要被调用的目标对象。Invorker?通过Invorker执行Command对象。适用于:
是将一个请求封装为一个对象,从而使你可用不同的请求对客户端进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。案例#in
cludeusingnamespacestd;#include"list"classVendor{p
ublic:voidsailbanana(){cout<<"卖香蕉"<out<<"卖苹果"<=0;};classBananaCommand:publicCommand{public:BananaCommand(V
endorv){m_v=v;}VendorgetV(Vendorv){returnm_v;}voidsetV(
Vendorv){m_v=v;}virtualvoidsail(){m_v->sailbanana();}protec
ted:private:Vendorm_v;};classAppleCommand:publicCommand{pub
lic:AppleCommand(Vendorv){m_v=v;}VendorgetV(Vendorv){retu
rnm_v;}voidsetV(Vendorv){m_v=v;}virtualvoidsail(){m_v->sa
ilapple();}protected:private:Vendorm_v;};classWaiter{public:Co
mmandgetCommand(){returnm_command;}voidsetCommand(Commandc)
{m_command=c;}voidsail(){m_command->sail();}protected:private:
Commandm_command;};classAdvWaiter{public:AdvWaiter(){m_list=
newlist;m_list->resize(0);}~AdvWaiter(){deletem_list
;}voidsetCommands(Commandc){m_list->push_back(c);}list>getCommands(){returnm_list;}voidsail(){for(list>::iteratorit=m_list->begin();it!=m_list->end();it++){(it)-
>sail();}}protected:private:listm_list;};//小商贩直接卖
水果voidmain25_01(){Vendorv=newVendor;v->sailapple();v->sailb
anana();deletev;return;}//小商贩通过命令卖水果voidmain25_02(){Vendor
v=newVendor;AppleCommandac=newAppleCommand(v);ac->sail()
;BananaCommandbc=newBananaCommand(v);bc->sail();deletebc;de
leteac;deletev;}//小商贩通过waiter卖水果voidmain25_03(){Vendorv=
newVendor;AppleCommandac=newAppleCommand(v);BananaCommand
bc=newBananaCommand(v);Waiterw=newWaiter;w->setCommand(a
c);w->sail();w->setCommand(bc);w->sail();deletew;deletebc;delet
eac;deletev;}//小商贩通过advwaiter批量下单卖水果voidmain25_04(){Vendor
v=newVendor;AppleCommandac=newAppleCommand(v);BananaComm
andbc=newBananaCommand(v);AdvWaiterw=newAdvWaiter;w->se
tCommands(ac);w->setCommands(bc);w->sail();deletew;deletebc;del
eteac;deletev;}voidmain(){//main25_01();//main25_02();//main25
_03();main25_04();system("pause");}练习医院护士(医导)、医生;护士把简历给医生;医生看病4.3
责任链模式概念ChainofResponsibility(CoR)模式也叫职责链模式或者职责连锁模式,是行为模式之一,该模式
构造一系列分别担当不同的职责的类的对象来共同完成一个任务,这些类的对象之间像链条一样紧密相连,所以被称作职责链模式。例1:比如客户
Client要完成一个任务,这个任务包括a,b,c,d四个部分。首先客户Client把任务交给A,A完成a部分之后,把任务交给B
,B完成b部分,...,直到D完成d部分。例2:比如政府部分的某项工作,县政府先完成自己能处理的部分,不能处理的部分交给省政府,省
政府再完成自己职责范围内的部分,不能处理的部分交给中央政府,中央政府最后完成该项工作。例3:软件窗口的消息传播。例4:SERVLE
T容器的过滤器(Filter)框架实现。角色和职责Handler?处理类的抽象父类。concreteHandler?具体的处理
类。责任链优缺点优点:1。责任的分担。每个类只需要处理自己该处理的工作(不该处理的传递给下一个对象完成),明确各类的责任范围,符合
类的最小封装原则。2。可以根据需要自由组合工作流程。如工作流程发生变化,可以通过重新分配对象链便可适应新的工作流程。3。类与类之间
可以以松耦合的形式加以组织。缺点:因为处理时以链的形式在对象间传递消息,根据实现方式不同,有可能会影响处理的速度。适用于:链条式处
理事情。工作流程化、消息处理流程化、事物流程化;案例#includeusingnamespacestd;
classCarHandle{public:virtualvoidHandleCar()=0;public:CarHan
dlesetNextHandle(CarHandlecarhandle){this->carhandle=carhan
dle;returnthis->carhandle;}protected:CarHandlecarhandle;};clas
sCarHandleHead:publicCarHandle{public:virtualvoidHandleCar(
){cout<<"处理车头"<carhandle!=NULL){carhandle->
HandleCar();}}};classCarHandleBody:publicCarHandle{public:vir
tualvoidHandleCar(){cout<<"处理车身"<carhandle
!=NULL){carhandle->HandleCar();}}};classCarHandleTail:public
CarHandle{public:virtualvoidHandleCar(){cout<<"处理车尾"<if(this->carhandle!=NULL){carhandle->HandleCar();}}};voidmain
(){CarHandleHeadhead=newCarHandleHead;CarHandleBodybody=
newCarHandleBody;CarHandleTailtail=newCarHandleTail;head->s
etNextHandle(body);body->setNextHandle(tail);tail->setNextHandle(
NULL);//处理head->HandleCar();deletehead;deletebody;deletetail;s
ystem("pause");return;}4.4策略模式概念Strategy模式也叫策略模式是行为模式之一,它对一系列的算法
加以封装,为所有算法定义一个抽象的算法接口,并通过继承该抽象算法接口对所有的算法加以封装和实现,具体的算法选择交由客户端决定(策略
)。Strategy模式主要用来平滑地处理算法的切换。角色和职责Strategy:策略(算法)抽象。ConcreteStrat
egy?各种策略(算法)的具体实现。Context?策略的外部封装类,或者说策略的容器类。根据不同策略执行不同的行为。策略由外部环
境决定。适用于:准备一组算法,并将每一个算法封装起来,使得它们可以互换。策略模式优缺点它的优点有:1.策略模式提供了管理相关的
算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免重复的代码。2.策略模式
提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个
子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为的逻辑
就和算法或行为的逻辑混合在一起,从而不可能再独立演化。继承使得动态改变算法或行为变得不可能。3.使用策略模式可以避免使用多重条件
转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面
,比使用继承的办法还要原始和落后。策略模式的缺点有:1.客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端
必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。2.策略模式造成很多
的策略类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,
可以使用享元模式来减少对象的数量。案例//SymmetricencryptionclassStrategy{public:vi
rtualvoidSymEncrypt()=0;};classDes:publicStrategy{public:
virtualvoidSymEncrypt(){cout<<"Des加密"<:publicStrategy{public:virtualvoidSymEncrypt(){cout<<"AES加
密"<=strategy;}voidOperator(){p->SymEncrypt();}private:Strategyp
;};//算法的实现和客户端的使用解耦合//使得算法变化,不会影响客户端voidmain(){/不符合开闭原则Str
ategystrategy=NULL;strategy=newAES;strategy->SymEncrypt();
deletestrategy;strategy=newDes;strategy->SymEncrypt();delete
strategy;/Strategystrategy=NULL;Contextctx=NULL;strategy
=newAES;ctx=newContext(strategy);ctx->Operator();deletestr
ategy;deletectx;cout<<"hello..."<练习商场促销有策略A(0.8折)策略B(消费满200,返券100),用策略模式模拟场景。4.5中介者模式mediator概念M
ediator模式也叫中介者模式,是由GoF提出的23种软件设计模式的一种。Mediator模式是行为模式之一,在Mediator
模式中,类之间的交互行为被统一放在Mediator的对象中,对象通过Mediator对象同其他对象交互,Mediator对象起着控
制器的作用。角色和职责GOOD:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显示的相互引用,从而降低耦合;而且可以独
立地改变它们之间的交互。Mediator抽象中介者?中介者类的抽象父类。concreteMediator?具体的中介者类。Coll
eague?关联类的抽象父类。concreteColleague具体的关联类。适用于:用一个中介对象,封装一些列对象(同事)的交换
,中介者是各个对象不需要显示的相互作用,从而实现了耦合松散,而且可以独立的改变他们之间的交换。模式优点1,将系统按功能分割成更小的
对象,符合类的最小设计原则2,对关联对象的集中控制3,减小类的耦合程度,明确类之间的相互关系:当类之间的关系过于复杂时,其中任何一
个类的修改都会影响到其他类,不符合类的设计的开闭原则,而Mediator模式将原来相互依存的多对多的类之间的关系简化为Media
tor控制类与其他关联类的一对多的关系,当其中一个类修改时,可以对其他关联类不产生影响(即使有修改,也集中在Mediator控制类
)。4,有利于提高类的重用性案例#includeusingnamespacestd;#include"
string"classPerson{public:Person(stringname,intsex,intcondi
t){m_name=name;m_sex=sex;m_condition=condit;}stringgetName
(){returnm_name;}intgetSex(){returnm_sex;}intgetCondit(){retu
rnm_condition;}virtualvoidgetParter(Personp)=0;protected:s
tringm_name;//intm_sex;//1男2女intm_condition;//123456789;};cla
ssMan:publicPerson{public:Man(stringname,intsex,intcond
it):Person(name,sex,condit){;}virtualvoidgetParter(Personp)
{if(this->getSex()==p->getSex()){cout<<"NoNoNo我不是同性恋"<<
endl;}if(this->getCondit()==p->getCondit()){cout<getN
ame()<<"和"<getName()<<"绝配"<->getName()<<"和"<getName()<<"不配"<};classWoman:publicPerson{public:Woman(stringname,intsex,
intcondit):Person(name,sex,condit){;}virtualvoidgetParter(P
ersonp){if(this->getSex()==p->getSex()){cout<<"NoNoNo我不
是同性恋"<getCondit()==p->getCondit()){cout<his->getName()<<"和"<getName()<<"绝配"<t<getName()<<"和"<getName()<<"不配"<rotected:};//以上WomanMan类的太紧密需要解耦合voidmain1901(){Womanw1=
newWoman("小芳",2,4);Manm1=newMan("张三",1,3);Manm2=ne
wMan("李四",1,4);w1->getParter(m1);w1->getParter(m2);deletew1;d
eletem1;deletem2;return;}classMediator;classPerson2{public:
Person2(stringname,intsex,intcondition,Mediatorm){m_name
=name;m_sex=sex;m_condition=condition;m_m=m;}stringgetNam
e(){returnm_name;}intgetSex(){returnm_sex;}intgetCondit(){ret
urnm_condition;}MediatorgetMediator(){returnm_m;}public:virtu
alvoidgetParter(Person2p)=0;protected:stringm_name;//intm_s
ex;//1男2女intm_condition;//123456789;Mediatorm_m;};classMed
iator{public:Mediator(){pMan=NULL;pWoman=NULL;}voidsetWoman
(Person2p){pWoman=p;}voidsetMan(Person2p){pMan=p;}voidg
etPartner(){if(pMan->getSex()==pWoman->getSex()){cout<<"NoN
oNo我不是同性恋"<getCondit()==pWoman->getCondit(
)){cout<getName()<<"和"<getName()<<"绝配"
<getName()<<"和"<getName
()<<"不配"<n;};classWoman2:publicPerson2{public:Woman2(stringname,int
sex,intcondition,Mediatorm):Person2(name,sex,condition,
m){;}virtualvoidgetParter(Person2p){this->getMediator()->setW
oman(this);this->getMediator()->setMan(p);this->getMediator()->ge
tPartner();}private:};classMan2:publicPerson2{public:Man2(str
ingname,intsex,intcondition,Mediatorm):Person2(name,se
x,condition,m){;}virtualvoidgetParter(Person2p){this->getMe
diator()->setMan(this);this->getMediator()->setWoman(p);this->get
Mediator()->getPartner();}private:};voidmain1902(){Mediatormed
iator=newMediator;Woman2w1=newWoman2("小芳",2,4,mediator
);Man2m1=newMan2("张三",1,3,mediator);Man2m2=newMan2("
李四",1,4,mediator);w1->getParter(m1);w1->getParter(m2);deletew
1;deletem1;deletem2;deletemediator;}voidmain(){//main1901();
//问题的引出main1902();//用中介者模式进行优化system("pause");}4.6观察者模式observer
概念Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。Obse
rver模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步。角色和职责Subject(被观察者)?
被观察的对象。当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。Subject需要维持(添加,删除,通知)一个观察者对象
的队列列表。ConcreteSubject?被观察者的具体实现。包含一些基本的属性状态及其他操作。Observer(观察者)?接口
或抽象类。当Subject的状态发生变化时,Observer对象将通过一个callback函数得到通知。ConcreteObser
ver?观察者的具体实现。得到通知后将完成一些具体的业务逻辑处理。典型应用-侦听事件驱动程序设计中的外部事件-侦听/监视某个对
象的状态变化-发布者/订阅者(publisher/subscriber)模型中,当一个外部事件(新的产品,消息的出现等等)被触发
时,通知邮件列表中的订阅者适用于:定义对象间一种一对多的依赖关系,使得每一个对象改变状态,则所有依赖于他们的对象都会得到通知。使用
场景:定义了一种一对多的关系,让多个观察对象(公司员工)同时监听一个主题对象(秘书),主题对象状态发生变化时,会通知所有的观察者,
使它们能够更新自己。案例#includeusingnamespacestd;#include"vect
or"#include"string"classSecretary;//玩游戏的同事类(观察者)classPlayserOb
server{public:PlayserObserver(stringname,Secretarysecretary){
m_name=name;m_secretary=secretary;}voidupdate(stringaction)
{cout<<"观察者收到action:"<ecretarym_secretary;};//秘书类(主题对象,通知者)classSecretary{public:void
addObserver(PlayserObservero){v.push_back(o);}voidNotify(stri
ngaction){for(vector::iteratorit=v.begin()
;it!=v.end();it++){(it)->update(action);}}voidsetAction(stri
ngaction){m_action=action;Notify(m_action);}private:stringm_a
ction;vectorv;};voidmain(){//subject被观察者Sec
retarys1=newSecretary;//具体的观察者被通知对象PlayserObserverpo1=n
ewPlayserObserver("小张",s1);//PlayserObserverpo2=newPlayser
Observer("小李",s1);s1->addObserver(po1);//s1->addObserver(po2);s1
->setAction("老板来了");s1->setAction("老板走了");cout<<"hello..."<system("pause");return;}练习利用观察者模式实现发布者/订阅者(publisher/subscriber)
模型。4.7备忘录模式mememto概念Memento模式也叫备忘录模式,是行为模式之一,它的作用是保存对象的内部状态,并在需要的
时候(undo/rollback)恢复对象以前的状态。应用场景如果一个对象需要保存状态并可通过undo或rollback等操作恢复
到以前的状态时,可以使用Memento模式。1)一个类需要保存它的对象的状态(相当于Originator角色)2)设计一个类,该类
只是用来保存上述对象的状态(相当于Memento角色)3)需要的时候,Caretaker角色要求Originator返回一个Mem
ento并加以保存4)undo或rollback操作时,通过Caretaker保存的Memento恢复Originator对象的状
态角色和职责Originator(原生者)需要被保存状态以便恢复的那个对象。Memento(备忘录)该对象由Originato
r创建,主要用来保存Originator的内部状态。Caretaker(管理者)负责在适当的时间保存/恢复Originator对
象的状态。适用于:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样就可以将以后的对象状态恢复到先前
保存的状态。适用于功能比较复杂的,但需要记录或维护属性历史的类;或者需要保存的属性只是众多属性中的一小部分时Originator可
以根据保存的Memo还原到前一状态。案例#includeusingnamespacestd;#inclu
de"string"classMememTo{public:MememTo(stringname,intage){thi
s->m_name=name;this->m_age=age;}voidsetName(stringname){thi
s->m_name=name;}stringgetName(){returnm_name;}voidsetAge(int
age){this->m_age=age;}intgetAge(){returnm_age;}protected:pr
ivate:stringm_name;intm_age;};classPerson{public:Person(stringn
ame,intage){this->m_name=name;this->m_age=age;}voidsetName
(stringname){this->m_name=name;}stringgetName(){returnm_name
;}voidsetAge(intage){this->m_age=age;}intgetAge(){returnm_
age;}voidprintT(){cout<<"name:"<<o(m_name,m_age);}//恢复备份voidSetMememTo(MememTomemto){m_name=
memto->getName();m_age=memto->getAge();}protected:private:strin
gm_name;intm_age;};//管理者classCaretaker{public:Caretaker(MememTo
mem){this->m_memto=mem;}MememTogetMememTo(){returnm_memto;}
voidsetMememTo(MememTomem){this->m_memto=mem;}protected:priv
ate:MememTom_memto;};voidmain23_01(){Personp=newPerson("张
三",18);p->printT();//创建备份Caretakerct=newCaretaker(p->create
MememTo());p->setAge(28);p->printT();//恢复信息p->SetMememTo(ct->getM
ememTo());p->printT();deletep;deletect->getMememTo();return;}v
oidmain23_02(){Personp=newPerson("张三",18);p->printT();//创建
备份MememTomembak=p->createMememTo();p->setAge(28);p->printT()
;//恢复信息p->SetMememTo(membak);p->printT();deletep;deletemembak;}
voidmain(){//main23_01();main23_02();system("pause");}4.8访问者模式vi
sitor概念Visitor模式也叫访问者模式,是行为模式之一,它分离对象的数据和行为,使用Visitor模式,可以不修改已有类的
情况下,增加新的操作角色和职责。角色和职责抽象访问者(Visitor)角色:声明了一个或者多个访问操作,形成所有的具体元素角色必须
实现的接口。具体访问者(ConcreteVisitor)角色:实现抽象访问者角色所声明的接口,也就是抽象访问者所声明的各个访问操作
。抽象节点(Element)角色:声明一个接受操作,接受一个访问者对象作为一个参量。具体节点(ConcreteElement)角色
:实现了抽象元素所规定的接受操作。结构对象(ObiectStructure)角色:有如下的一些责任,可以遍历结构中的所有元素;如果
需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或者一个聚集,如列(List)或集合(S
et)。适用于:把数据结构和作用于数据结构上的操作进行解耦合;适用于数据结构比较稳定的场合访问者模式总结:访问者模式优点是增
加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者。访问者模式将有关的行为集中到一个访问者对象中。那访问者模式的缺点是是
增加新的数据结构变得困难了优缺点访问者模式有如下的优点:1,访问者模式使得增加新的操作变得很容易。如果一些操作依赖于一个复杂的结构
对象的话,那么一般而言,增加新的操作会很复杂。而使用访问者模式,增加新的操作就意味着增加一个新的访问者类,因此,变得很容易。2,访
问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。3,访问者模式可以跨过几个类的等级结构访问属于不同的等级
结构的成员类。迭代子只能访问属于同一个类型等级结构的成员对象,而不能访问属于不同等级结构的对象。访问者模式可以做到这一点。4,积累
状态。每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程中将执行操作的状态积累在自己内部,而不是分散到很多的节点对
象中。这是有益于系统维护的优点。访问者模式有如下的缺点:1,增加新的节点类变得很困难。每增加一个新的节点都意味着要在抽象访问者角色
中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作。2,破坏封装。访问者模式要求访问者对象访问并调用每一个节点对象
的操作,这隐含了一个对所有节点对象的要求:它们必须暴露一些自己的操作和内部状态。不然,访问者的访问就变得没有意义。由于访问者对象自
己会积累访问操作所需的状态,从而使这些状态不再存储在节点对象中,这也是破坏封装的。案例案例需求:比如有一个公园,有一到多个不同的组
成部分;该公园存在多个访问者:清洁工A负责打扫公园的A部分,清洁工B负责打扫公园的B部分,公园的管理者负责检点各项事务是否完成,上
级领导可以视察公园等等。也就是说,对于同一个公园,不同的访问者有不同的行为操作,而且访问者的种类也可能需要根据时间的推移而变化(行
为的扩展性)。根据软件设计的开闭原则(对修改关闭,对扩展开放),我们怎么样实现这种需求呢?#includeu
singnamespacestd;#include"list"#include"string"classParkEle
ment;//不同的访问者访问公园完成不同的动作classVisitor{public:virtualvoidvisi
t(ParkElementpark)=0;};classParkElement//每一个{public:virtual
voidaccept(Visitorv)=0;};classParkA:publicParkElement{p
ublic:virtualvoidaccept(Visitorv){v->visit(this);}};classPar
kB:publicParkElement{public:virtualvoidaccept(Visitorv){v-
>visit(this);}};classPark:publicParkElement{public:Park(){m_
list.clear();}voidsetPart(ParkElemente){m_list.push_back(e);}p
ublic:voidaccept(Visitorv){for(list::iterator
it=m_list.begin();it!=m_list.end();it++){(it)->accept(v);}}
private:listm_list;};classVisitorA:publicVisi
tor{public:virtualvoidvisit(ParkElementpark){cout<<"清洁工A访问公
园A部分,打扫卫生完毕"<rtualvoidvisit(ParkElementpark){cout<<"清洁工B访问公园B部分,打扫卫生完
毕"<lvoidvisit(ParkElementpark){cout<<"管理员检查整个公园卫生打扫情况"<l;}};voidmain(){VisitorAvisitorA=newVisitorA;VisitorBvisi
torB=newVisitorB;ParkApartA=newParkA;ParkBpartB=newP
arkB;//公园接受访问者a访问partA->accept(visitorA);partB->accept(visitorB);
VisitorManagervisitorManager=newVisitorManager;Parkpark=
newPark;park->setPart(partA);park->setPart(partB);park->accept(
visitorManager);cout<<"hello..."<includeusingnamespacestd;#include"string"#include"
list"//客户去银行办理业务//m个客户//n个柜员//将要对象和要处理的操作分开,不同的柜员可以办理不同来访者的业务cl
assElement;//访问者访问柜员classVisitor{public:virtualvoidvisit(Ele
mentelement)=0;};//柜员接受客户访问classElement{public:virtualvoid
accept(Visitorv)=0;virtualstringgetName()=0;};//柜员A员工cla
ssEmployeeA:publicElement{public:EmployeeA(stringname){m_nam
e=name;}virtualvoidaccept(Visitorv){v->visit(this);}virtua
lstringgetName(){returnm_name;}private:stringm_name;};//柜员B员
工classEmployeeB:publicElement{public:EmployeeB(stringname){m
_name=name;}virtualvoidaccept(Visitorv){v->visit(this);}str
inggetName(){returnm_name;}private:stringm_name;};classVisito
rA:publicVisitor{public:virtualvoidvisit(Elementelement){c
out<<"通过"<getName()<<"做A业务"<torB:publicVisitor{public:virtualvoidvisit(Elementelement)
{cout<<"通过"<getName()<<"做B业务"<n26_01(){EmployeeAeA=newEmployeeA("柜员A");VisitorAvA=new
VisitorA;VisitorBvB=newVisitorB;eA->accept(vA);eA->accept(vB
);deleteeA;deletevA;deletevB;return;}//柜员B员工classEmployees
:publicElement{public:Employees(){m_list=newlist;
}virtualvoidaccept(Visitorv){for(list::iteratori
t=m_list->begin();it!=m_list->end();it++){(it)->accept(v
);}}stringgetName(){returnm_name;}public:voidaddElement(Elemen
te){m_list->push_back(e);}voidremoveElement(Elemente){m_list
->remove(e);}private:listm_list;stringm_name;};void
main26_02(){EmployeeAeA=newEmployeeA("柜员A");EmployeeAeB=
newEmployeeA("柜员B");Employeeses=newEmployees;es->addElement
(eA);es->addElement(eB);VisitorAvA=newVisitorA;VisitorBvB
=newVisitorB;es->accept(vA);cout<<"-------------"<>accept(vB);deleteeA;deleteeB;deletevA;deletevB;return;}voi
dmain(){//main26_01();main26_02();system("pause");}4.9状态模式state概
念State模式也叫状态模式,是行为设计模式的一种。State模式允许通过改变对象的内部状态而改变对象的行为,这个对象表现得就好像
修改了它的类一样。状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转译到表现不同状态的一
系列类当中,可以把复杂的判断逻辑简化。角色和职责Context:用户对象拥有一个State类型的成员,以标识对象的当前状态;St
ate:接口或基类封装与Context的特定状态相关的行为;ConcreteState:接口实现类或子类实现了一个与Contex
t某个状态相关的行为。适用于:对象的行为,依赖于它所处的当前状态。行为随状态改变而改变的场景。适用于:通过用户的状态来改变对象的
行为。案例#includeusingnamespacestd;classWorker;classSt
ate{public:virtualvoiddoSomeThing(Workerw)=0;};classWorker
{public:Worker();intgetHour(){returnm_hour;}voidsetHour(intho
ur){m_hour=hour;}StategetCurrentState(){returnm_currstate;}v
oidsetCurrentState(Statestate){m_currstate=state;}voiddoSom
eThing()//{m_currstate->doSomeThing(this);}private:intm_hour;Sta
tem_currstate;//对象的当前状态};classState1:publicState{public:vo
iddoSomeThing(Workerw);};classState2:publicState{public:
voiddoSomeThing(Workerw);};voidState1::doSomeThing(Workerw)
{if(w->getHour()==7||w->getHour()==8){cout<<"吃早饭"<}else{deletew->getCurrentState();//状态1不满足要转到状态2w->setCurre
ntState(newState2);w->getCurrentState()->doSomeThing(w);//}}vo
idState2::doSomeThing(Workerw){if(w->getHour()==9||w->get
Hour()==10){cout<<"工作"<getCurrentStat
e();//状态2不满足要转到状态3后者恢复到初始化状态w->setCurrentState(newState1);/
/恢复到当初状态cout<<"当前时间点:"<getHour()<<"未知状态"<er::Worker(){m_currstate=newState1;}voidmain(){Workerw1=n
ewWorker;w1->setHour(7);w1->doSomeThing();w1->setHour(9);w1->doS
omeThing();deletew1;cout<<"hello..."<n;}4.10解释模式interpreter概念角色和职责Context解释器上下文环境类。用来存储解释器的上下文环境,比如需要
解释的文法等。AbstractExpression?解释器抽象类。ConcreteExpression解释器具体实现类。案例#i
ncludeusingnamespacestd;#include"string"classConte
xt{public:Context(intnum){m_num=num;}public:voidsetNum(intnu
m){m_num=num;}intgetNum(){returnm_num;}voidsetRes(intres){m
_res=res;}intgetRes(){returnm_res;}private:intm_num;intm_re
s;};classExpression{public:virtualvoidinterpreter(Contextcon
text)=0;};classPlusExpression:publicExpression{public:virtu
alvoidinterpreter(Contextcontext){intnum=context->getNum()
;num++;context->setNum(num);context->setRes(num);}};classMinus
Expression:publicExpression{public:virtualvoidinterpreter(Co
ntextcontext){intnum=context->getNum();num--;context->setN
um(num);context->setRes(num);}};voidmain(){Contextpcxt=newC
ontext(10);Expressione1=newPlusExpression;e1->interpreter(pc
xt);cout<<"PlusExpression:"<getRes()<ne2=newMinusExpression;e2->interpreter(pcxt);cout<<"MinusE
xpression:"<getRes()<"pause");return;}4.11迭代器模式iterator概念Iterator模式也叫迭代模式,是行为模式之一,它把
对容器中包含的内部对象的访问委让给外部类,使用Iterator(遍历)按顺序进行遍历访问的设计模式。在应用Iterator模式之前
,首先应该明白Iterator模式用来解决什么问题。或者说,如果不使用Iterator模式,会存在什么问题。1.由容器自己实现顺序
遍历。直接在容器类里直接添加顺序遍历方法2.让调用者自己实现遍历。直接暴露数据细节给外部。以上方法1与方法2都可以实现对遍历,这
样有问题呢?1,容器类承担了太多功能:一方面需要提供添加删除等本身应有的功能;一方面还需要提供遍历访问功能。2,往往容器在实现遍历
的过程中,需要保存遍历状态,当跟元素的添加删除等功能夹杂在一起,很容易引起混乱和程序运行错误等。Iterator模式就是为了有效地
处理按顺序进行遍历访问的一种设计模式,简单地说,Iterator模式提供一种有效的方法,可以屏蔽聚集对象集合的容器类的实现细节,而能对容器内包含的对象元素按顺序进行有效的遍历访问。所以,Iterator模式的应用场景可以归纳为满足以下几个条件:-访问容器中包含的内部对象-按顺序访问角色和职责GOOD:提供一种方法顺序访问一个聚敛对象的各个元素,而又不暴露该对象的内部表示。为遍历不同的聚集结构提供如开始,下一个,是否结束,当前一项等统一接口。Iterator(迭代器接口):该接口必须定义实现迭代功能的最小定义方法集比如提供hasNext()和next()方法。ConcreteIterator(迭代器实现类):迭代器接口Iterator的实现类。可以根据具体情况加以实现。Aggregate(容器接口):定义基本功能以及提供类似Iteratoriterator()的方法。concreteAggregate(容器实现类):容器接口的实现类。必须实现Iteratoriterator()方法。//在迭代器中持有一个集合的引用;所以通过迭代器,就可以访问集合案例#includeusingnamespacestd;typedefintObject;#defineSIZE5//注意类的顺序classMyIterator{public:virtualvoidFirst()=0;virtualvoidNext()=0;virtualboolIsDone()=0;virtualObjectCurrentItem()=0;};classAggregate{public:virtualObjectgetItem(intindex)=0;virtualMyIteratorCreateIterator()=0;virtualintgetSize()=0;};classContreteIterator:publicMyIterator{public:ContreteIterator(Aggregateag){_ag=ag;_idx=0;}~ContreteIterator(){_ag=NULL;_idx=0;}virtualvoidFirst(){_idx=0;}virtualvoidNext(){if(_idx<_ag->getSize()){_idx++;}}virtualboolIsDone(){return(_idx==_ag->getSize());}virtualObjectCurrentItem(){return_ag->getItem(_idx);}protected:private:int_idx;Aggregate_ag;};classConcreteAggregate:publicAggregate{public:ConcreteAggregate(){for(inti=0;iCreateIterator();//通过迭代器遍历集合for(;!(it->IsDone());it->Next()){cout<CurrentItem()<<"";}//清理相关资源deleteit;deleteag;}voidmain(){main21();system("pause");return;}EngPerson{Public:Voiddowork1(Carcar){Car.Run();}Voiddowork2(){m_car.run()}Private:Carm_car;}5类与类之间关系类与类之间的关系对于理解面向对象具有很重要的作用,以前在面试的时候也经常被问到这个问题,在这里我就介绍一下。类与类之间存在以下关系:(1)泛化(Generalization)(2)关联(Association)(3)依赖(Dependency)(4)聚合(Aggregation)UML图与应用代码例子:UML表示和代码表示//依赖(虚线):一个类是另外一个类的函数参数或者函数返回值//关联(实线)关联张三有车一个类是另外一个类的成员变量//聚合(菱形实线):整体和部分的关系汽车发动机(汽车可以选择各个型号的发动机)//组合(实心形加实线):生命体,整体和部分的关系汽车发动机(人和五脏六腑)1泛化(Generalization)[泛化]表示类与类之间的继承关系,接口与接口之间的继承关系,或类对接口的实现关系。一般化的关系是从子类指向父类的,与继承或实现的方法相反。[具体表现]父类父类实例=new子类()[UML图](图1.1)图1.1Animal类与Tiger类,Dog类的泛化关系[代码表现]class?Animal{}class?Tiger?extends?Animal{}public?class?Test{?public?void?test()?{?Animal?a=new?Tiger();?}}2依赖(Dependency)对于两个相对独立的对象,当一个对象负责构造另一个对象的实例,或者依赖另一个对象的服务时,这两个对象之间主要体现为依赖关系。[具体表现]依赖关系表现在局部变量,方法的参数,以及对静态方法的调用[现实例子]比如说你要去拧螺丝,你是不是要借助(也就是依赖)螺丝刀(Screwdriver)来帮助你完成拧螺丝(screw)的工作[UML表现](图1.2)图1.2Person类与Screwdriver类的依赖关系[代码表现]public?class?Person{?/?拧螺丝?/?public?void?screw(Screwdriver?screwdriver){?screwdriver.screw();?}Voiddrive(Car&mycar){}}3关联(Association)对于两个相对独立的对象,当一个对象的实例与另一个对象的一些特定实例存在固定的对应关系时,这两个对象之间为关联关系。[具体表现]关联关系是使用实例变量来实现[现实例子]比如客户和订单,每个订单对应特定的客户,每个客户对应一些特定的订单;再例如公司和员工,每个公司对应一些特定的员工,每个员工对应一特定的公司[UML图](图1.3)图1.3公司和员工的关联关系[代码表现]public?class?Company{?private?Employee?employee;?public?Employee?getEmployee(){?return?employee;?}?public?void?setEmployee(Employee?employee){?this.employee=employee;?}?//公司运作?public?void?run(){?employee.startWorking();?}}测试案例:Person{Public:Voiddowork1(Carcar)//借别人的车去上班可以借用A、B的车,依赖于别人{Car.Run();}Voiddowork2(){m_car.run()//开自己的车上班}Private:Carm_car;}Person和Car是关联关系Person和car是依赖关系Voiddowork1(Carcar)4聚合(Aggregation)当对象A被加入到对象B中,成为对象B的组成部分时,对象B和对象A之间为聚集关系。聚合是关联关系的一种,是较强的关联关系,强调的是整体与部分之间的关系。[具体表现]与关联关系一样,聚合关系也是通过实例变量来实现这样关系的。关联关系和聚合关系来语法上是没办法区分的,从语义上才能更好的区分两者的区别。[关联与聚合的区别](1)关联关系所涉及的两个对象是处在同一个层次上的。比如人和自行车就是一种关联关系,而不是聚合关系,因为人不是由自行车组成的。聚合关系涉及的两个对象处于不平等的层次上,一个代表整体,一个代表部分。比如电脑和它的显示器、键盘、主板以及内存就是聚集关系,因为主板是电脑的组成部分。(2)对于具有聚集关系(尤其是强聚集关系)的两个对象,整体对象会制约它的组成对象的生命周期。部分类的对象不能单独存在,它的生命周期依赖于整体类的对象的生命周期,当整体消失,部分也就随之消失。比如张三的电脑被偷了,那么电脑的所有组件也不存在了,除非张三事先把一些电脑的组件(比如硬盘和内存)拆了下来。[UML图](图1.4)图1.3电脑和组件的聚合关系[代码表现]public?class?Computer{?private?CPU?cpu;?public?CPU?getCPU(){?return?cpu;?}?public?void?setCPU(CPU?cpu){?this.cpu=cpu;?}?//开启电脑?public?void?start(){?//cpu运作?cpu.run();?}}5组合关系代表整体的对象负责代表部分对象的生命周期。公司不存在,部门也没有意义了。再例如:人和五脏六腑、四肢的关系。组合关系。6UML图1用例图2类图依赖关联聚合组合3对象图4时序图5活动图6状态图7协作图8和9包图和组件图10部署图1
献花(0)
+1
(本文系zhengtu342原创)