本文代码所在的目录
https://gitee.com/blueboz/designmode.git
推荐参考文章
http://c.biancheng.net/view/1402.html
前言
身为程序员,我们不需要华丽的编程技巧,高深的代码,对于我们来说只需要熟练的掌握业界给予我们总结的23种设计模式,才是最重要的。因为掌握这23种设计模式,你就可以成为不一般的开发人员了。笔者工作有3年多了,至今对设计模式了解甚少,惭愧啊。如今,我痛下定决心,要吃透这23种设计模式。回想从业几年来,有多少功能做的不尽如人意,有多少功能的设计都是用简简单单的结构去写,那些丝毫无一点点设计理念的代码,根本就算不上是程序。直到再次复习到设计模式的时候,我总会有一种很熟悉的感觉,似乎自己之前的一些功能,本来可以如此巧妙的去处理。现在开始,我们就一起重新的复习一遍把。
提要
本案例中使用到javabean 宏,其特点是定义了属性之后,自动为我们生成get set 方法。
#define PropertyBuilderByName(type, name, access_permission)\
access_permission:\
type m_##name;\
public:\
inline void set##name(type v) {\
m_##name = v;\
}\
inline type get##name() {\
return m_##name;\
}\
#define PointerPropertyBuilderByName(type, name, access_permission)\
access_permission:\
type* m_##name;\
public:\
inline void set##name(type* v){\
m_##name = v;\
}\
inline type* get##name(){\
return m_##name;\
}\
设计模式
模式
在一定环境中解决某一问题的方案,包括三个基本元素–问题,解决方案和环境。
大白话:在一定环境下,用固定套路解决问题。
设计模式(Design pattern)
是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计 模式是为了可重用代码、让代码更容易被他人理解、保证代 码可靠性。 毫无疑问,设计模 式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;
设计模式的分类
创建型模式 : 通常和对象的创建有关,涉及到对象实例化的方式。(共 5 种模式)
结构型模式: 描述的是如何组合类和对象以获得更大的结构。(共 7 种模式)
行为型模式: 用来对类或对象怎样交互和怎样分配职责进行描述。(共 11 种模式)
创建型模式
该模式用来处理对象的创建过程,主要包含以下五种设计模式:(单原建抽象工厂)
1,工厂方法模式(Factory Method Pattern)的用意是定义一个创建产品对象的工厂接口, 将实际创建工作推迟到子类中。
2,抽象工厂模式(Abstract Factory Pattern)的意图是提供一个创建一系列相关或者相互依 赖的接口,而无需指定它们具体的类。
3,建造者模式(Builder Pattern)的意图是将一个复杂的构建与其表示相分离,使得同样的 构建过程可以创建不同的表示。
4,原型模式(Prototype Pattern)是用原型实例指定创建对象的种类,并且通过拷贝这些原 型创建新的对象。
5,单例模式(Singleton Pattern)是保证一个类仅有一个实例,并提供一个访问它的全局访 问点。
结构型模式
6,代理模式(Proxy Pattern)就是为其他对象提供一种代理以控制对这个对象的访问。
7,装饰者模式(Decorator Pattern)动态的给一个对象添加一些额外的职责。就增加功能来 说,此模式比生成子类更为灵活。
8,适配器模式(Adapter Pattern)是将一个类的接口转换成客户希望的另外一个接口。使得 原本由于接口不兼容而不能一起工作的那些类可以一起工作。
9,桥接模式(Bridge Pattern)是将抽象部分与实际部分分离,使它们都可以独立的变化。
10,组合模式(Composite Pattern)是将对象组合成树形结构以表示“部分–整体”的层次结 构。使得用户对单个对象和组合对象的使用具有一致性。
11,外观模式(Facade Pattern)是为子系统中的一组接口提供一个一致的界面,此模式定义 了一个高层接口,这个接口使得这一子系统更加容易使用。
12,享元模式(Flyweight Pattern)是以共享的方式高效的支持大量的细粒度的对象。
行为模式
13,模板方法模式(Template Method Pattern)使得子类可以不改变一个算法的结构即可重 定义该算法的某些特定步骤。
14,命令模式(Command Pattern)是将一个请求封装为一个对象,从而使你可用不同的请 求对客户端进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
15,责任链模式(Chain of Responsibility Pattern),在该模式里,很多对象由每一个对象对其 下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理 此请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。
16,策略模式(Strategy Pattern)就是准备一组算法,并将每一个算法封装起来,使得它们 可以互换。
17,中介者模式(Mediator Pattern)就是定义一个中介对象来封装系列对象之间的交互。终 结者使各个对象不需要显示的相互调用 ,从而使其耦合性松散,而且可以独立的改变他们 之间的交互。
18,观察者模式(Observer Pattern)定义对象间的一种一对多的依赖关系,当一个对象的状 态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
19,备忘录模式(Memento Pattern)是在不破坏封装的前提下,捕获一个对象的内部状态, 并在该对象之外保存这个状态。
20,访问者模式(Visitor Pattern)就是表示一个作用于某对象结构中的各元素的操作,它使 你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
21,状态模式(State Pattern)就是对象的行为,依赖于它所处的状态。
22,解释器模式(Interpreter Pattern)就是描述了如何为简单的语言定义一个语法,如何在 该语言中表示一个句子,以及如何解释这些句子。
23,迭代器模式(Iterator Pattern)是提供了一种方法顺序来访问一个聚合对象中的各个元 素,而又不需要暴露该对象的内部表示。
设计模式这么多,怎么巧记哈
————————————————
原文链接:https://blog.csdn.net/wzgbgz/article/details/79276341
1,创建型模式有五种:工厂方法模式 、抽象工厂模式 、单例模式 、建造者模式 、原型模式
口诀:原来的建设工人单独抽奖
解释:原(原型模式)来的建(建造者模式)设工(工厂方法模式)人单(单例模式)独抽(抽象方法模式)奖。
2,结构型模式有七中:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
口诀:带上适当的装备组合可以让外国侨胞享受(游戏)
解释:带(代理模式)上适(适配器模式)当的装(装饰模式)备组(组合模式)合可以让外(外观模式)国侨(桥接模式)胞享(享元模式)受(游戏)
3,行为型模式有十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式
口诀:多次命令和责备中,车模见状慌忙解开(衣服)
解释:多次(迭:多次的意思,迭代模式)命(命令模式)令和责(责任链模式)备(备忘录模式)中(中介者模式),车(策略模式)模(模板方法模式)见(观察着模式)状(状态模式)慌(访问者模式)忙解(解释器模式)开(衣服)。
————————————————
原文链接:https://blog.csdn.net/wzgbgz/article/details/79276341
设计模式的基本原则
最终目的:高内聚,低耦合
- 开放封闭原则 (OCP,Open For Extension, Closed For Modification Principle)
类的改动是通过增加代码进行的,而不是修改源代码。 - 单一职责原则 (SRP,Single Responsibility Principle)
类的职责要单一,对外只提供一种功能,而引起类变化的原因都应该只有一个。 - 依赖倒置原则(DIP,Dependence Inversion Principle)
依赖于抽象(接口),不要依赖具体的实现(类),也就是针对接口编程。 - 接口隔离原则(ISP,Interface Segegation Principle)
不应该强迫客户的程序依赖他们不需要的接口方法。一个接口应该只提供一种对外功能,
不应该把所有操作都封装到一个接口中去。 - 里氏替换原则(LSP, Liskov Substitution Principle)
任何抽象类出现的地方都可以用他的实现类进行替换。实际就是虚拟机制,语言级别实 现面向对象功能。 - 优先使用组合而不是继承原则(CARP,Composite/Aggregate Reuse Principle)
如果使用继承,会导致父类的任何变换都可能影响到子类的行为。 如果使用对象组合,就降低了这种依赖关系。 - 迪米特法则(LOD,Law of Demeter)
一个对象应当对其他对象尽可能少的了解,从而降低各个对象之间的耦合,提高系统的
可维护性。例如在一个程序中,各个模块之间相互调用时,通常会提供一个统一的接口来实 现。这样其他模块不需要了解另外一个模块的内部实现细节,这样当一个模块内部的实现发 生改变时,不会影响其他模块的使用。(黑盒原理)
开闭原则案例
依赖倒置原则
迪米特法则
和陌生人说话
不和陌生人说话
与依赖倒转原则结核 某人和抽象陌生人说话,让某人与陌生人解耦合。
创建型模式
单例模式
单例模式是一种对象创建型模式,使用单例模式,可以保证为一个类只生成唯一的实例 对象。也就是说,在整个程序空间中,该类只存在一个实例对象。
GoF 对单例模式的定义是:保证一个类、只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。
为什么要使用单例
在应用系统开发中,我们常常有以下需求:
- 在多个线程之间,比如初始化一次 socket 资源;比如 servlet 环境,共享同一个资源或者 操作同一个对象
- 在整个程序空间使用全局变量,共享资源
- 大规模系统中,为了性能的考虑,需要节省对象的创建时间等等。
因为 Singleton 模式可以保证为一个类只生成唯一的实例对象,所以这些情况,Singleton 模 式就派上用场了。
实现单例的基本步骤
- 构造函数私有化
- 提供一个全局的静态方法(全局访问点)
- 在类中定义一个静态指针,指向本类的变量的静态变量指针
饿汉式单例和懒汉式单例
#include <iostream> using namespace std;
//懒汉式
class Singelton {
private:
Singelton() {
m_singer = NULL;
m_count = 0;
cout << "构造函数 Singelton ... do" << endl;
}
public:
static Singelton *getInstance() {
if (m_singer == NULL ) //懒汉式:1 每次获取实例都要判断 2 多线程会有问题
{
m_singer = new Singelton;
}
return m_singer;
}
static void printT() {
cout << "m_count: " << m_count << endl;
}
private:
static Singelton *m_singer; static int m_count;
};
饿汉式
using namespace std;
class Singelton2 {
private:
Singelton2() {
m_singer = NULL;
m_count = 0;
cout << "构造函数 Singelton ... do" << endl;
}
public:
static Singelton2 *getInstance() {
if (m_singer == NULL ) {
m_singer = new Singelton2; }
return m_singer; }
static void Singelton2::FreeInstance() {
if (m_singer != NULL) {
delete m_singer;
m_singer = NULL;
m_count = 0;
}
}
static void printT() {
cout << "m_count: " << m_count << endl; }
private:
static Singelton2 *m_singer; static int m_count;
};
多线程下的懒汉式单例和饿汉式单例
多线程的情况下,饿汉式会存在线程安全的问题
如何解决这个问题?通常是采取加锁的方式进行处理
static Singleton *Instantialize() {
if(pInstance == NULL) //double check
{
//加锁
cs.Lock();
if(pInstance==NULL){
pInstance = new Singleton();
}
//释放锁
cs.Unlock();
}
return pInstance; }
简单工厂模式
是什么
简单工厂模式属于类的创建型模式,又叫做静态工厂方法模式。通过专门定义一个类来负 责创建其他类的实例,被创建的实例通常都具有共同的父类。
- 工厂(Creator)角色 简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调
用,创建所需的产品对象。 - 抽象(Product)角色
简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。 - 具体产品(Concrete Product)角色
简单工厂模式所创建的具体实例对象 - 在这个模式中,工厂类是整个模式的关键所在。它包含必要的判断逻辑,能够根据外界 给定的信息,决定究竟应该创建哪个具体类的对象。用户在使用时可以直接根据工厂类去创 建所需的实例,而无需了解这些对象是如何创建以及如何组织的。有利于整个软件体系结构 的优化。不难发现,简单工厂模式的缺点也正体现在其工厂类上,由于工厂类集中了所有实 例的创建逻辑,所以“高内聚”方面做的并不好。另外,当系统中的具体产品类不断增多时
class Fruit{
public:
virtual~Fruit()=0;
virtual void getFruit()=0;
};
class Banana:public Fruit{
public:
void getFruit(){
cout<<"香蕉"<<endl;
}
};
class Pear:public Fruit{
// Fruit interface
public:
void getFruit(){
cout<<"梨子"<<endl;
}
};
//工厂不是一个抽象工厂
/**
* @brief The Factory class
*/
class Factory{
static Fruit* Create(char *name){
Fruit *fruit=NULL;
if(strcmp(name,"pear")==0){
fruit=new Pear;
}else if(strcmp(name,"banana")==0){
fruit=new Banana;
}else{
}
}
};
工厂模式
工厂方法模式同样属于类的创建模式,又被成为多态工厂模式,工厂模式的意义是定义一个创建产品的工厂接口,将创建工作推迟到子类中
核心工厂类不再负责产品的创建,这样,核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,好处是,可以在不修改具体工厂角色的情况下引入新的产品
类图角色和职责
抽象工厂(Creator)角色
工厂方法模式的核心,任何工厂类都必须实现这个接口。
具体工厂( Concrete Creator)角色
具体工厂类是抽象工厂的一个实现,负责实例化产品对象。
抽象(Product)角色
工厂方法模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
具体产品(Concrete Product)角色
工厂方法模式所创建的具体实例对象
工厂模式与简单工厂之比较
工厂方法类核心是一个抽象工厂,而简单工厂是放一个具体的工厂
抽象工厂需要扩展的时候,仅仅需要在添加新产品对象的时候,添加一个具体对象和具体对象的工厂即可,原有的工厂无需修改,符合开闭原则
如下代码,核心类由如下两个类组成,子类靠实现此两接口完成。
class Fruit{
public:
virtual ~Fruit()=0;
};
class FruitFactory{
public:
virtual ~FruitFactory()=0;
virtual Fruit* getFruit()=0;
};
抽象工厂模式
抽象工厂模式是所有形态的工厂模式中最为抽象和最其一般性的。抽象工厂模式可以向 客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,能够创建多个产品 族的产品对象。
产品族和产品等级结构
模式中包含的角色与职责
- 抽象工厂(Creator)角色
抽象工厂模式的核心,包含对多个产品结构的声明,任何工厂类都必须实现这个接口。 - 具体工厂( Concrete Creator)角色
具体工厂类是抽象工厂的一个实现,负责实例化某个产品族中的产品对象。 - 抽象(Product)角色
抽象模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。 - 具体产品(Concrete Product)角色
抽象模式所创建的具体实例对象
/**
* 总结上来说:抽象工厂是一个大型工厂,其不仅仅可以生产某一种单一的产品
* 其是可以生产某一类产品,我们的抽象工厂的定义扩展为不同的类型的工厂生产
* 出不同工厂生产的产品
*/
class Fruit{
public:
virtual ~Fruit()=0;
virtual void sayname()=0;
};
class FruitFactory{
public:
virtual Fruit* getApple()=0;
virtual Fruit* getBanana()=0;
virtual ~FruitFactory()=0;
};
class SouthBanana:public Fruit{
public:
virtual void sayname() {
cout<<"South Banana"<<endl;
}
};
class SouthApple:public Fruit{
public:
virtual void sayname(){
cout<<"South Apple"<<endl;
}
};
class NorthBanana:public Fruit{
public:
virtual void sayname() {
cout<<"North Banana"<<endl;
}
};
class NorthApple:public Fruit{
public:
void sayname(){
cout<<"North Apple"<<endl;
}
};
class SouthFruitFactory:public FruitFactory{
public:
Fruit *getApple(){
return new SouthApple;
}
Fruit *getBanana(){
return new SouthBanana;
}
};
class NorthFruitFactory:public FruitFactory{
public:
Fruit *getApple(){
return new NorthApple;
}
Fruit *getBanana(){
return new NorthBanana;
}
};
建造者模式
Builder 模式也叫建造者模式或者生成器模式,是由 GoF 提出的 23 种设计模式中的一种。 Builder 模式是一种对象创建型模式之一,用来隐藏复合对象的创建过程,它把复合对象的 创建过程加以抽象,通过子类继承和重载的方式,动态地创建具有复合属性的对象。
builder 模式是为对象的创建而设计的模式,创建的是一个复合对象,被创建的对象为一个具有简单复合属性的复合对象,关注对象创建的各部分,不同工厂对产品属性有不同的创建方法。
角色和职责
- Builder:为创建产品各个部分,统一抽象接口。
- ConcreteBuilder:具体的创建产品的各个部分,部分 A, 部分 B,部分 C。
- Director:构造一个使用 Builder 接口的对象。
- Product:表示被构造的复杂对象。
ConcreteBuilder 创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类, 包括将这些部件装配成最终产品的接口
创建者模式与工厂模式的区别
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
class Builder {
public:
virtual void makeFloor() = 0; virtual void makeWall() = 0;
virtual void makeDoor() = 0; virtual House *GetHouse() = 0;
};
//公寓
class FlatBuild : public Builder {
//别墅
class VillaBuild : public Builder {
class Director {
public:
void Construct(Builder *builder) {
builder->makeFloor();
builder->makeWall();
builder->makeDoor();
}
//最终实现效果
//客户直接造房子
House *pHose = new House;
pHose->setDoor("wbm 门");
pHose->setFloor("wbmFloor");
pHose->setWall("wbmWall");
delete pHose;
//工程队直接造房子
Builder *builder = new FlatBuild;
builder->makeFloor();
builder->makeWall();
builder->makeDoor();
//指挥者(设计师)指挥 工程队 和 建房子
Director *director = new Director;
//建公寓
Builder *builder = new FlatBuild;
director->Construct(builder); //设计师 指挥 工程队干活
House *house = builder->GetHouse();
cout << house->getFloor() << endl;
delete house;
delete builder;
builder = new VillaBuild;
director->Construct(builder); //设计师 指挥 工程队干活
house = builder->GetHouse();
cout << house->getFloor() << endl;
delete house;
delete builder;
delete director;
system("pause");
由于工程队的基本操作已经被抽象成方法,所以工厂师在操作的时候,只需要调用对应接口的方法,从而达到给工程师某个类型的实例的时候,工程师可以按照对应类型的要求去实例化。
原型模式prototype
Prototype 是一种对象创建型模式,他采取复制原型对象的方法来创建对象的实例。使用Prototype模式创建的实例,具有与原型一样的数据。
- 由原型对象自身创建目标对象,也就是说,对象创建这一动作发自对象本身
- 目标对象是原型对象的一个克隆。也就是说,通过Prototype模式创建的对象,不仅仅与原型具有一样的结构,还具有一样的值。
- 根据对象克隆深度层次不同,有深度克隆和浅度克隆的区别
角色与职责
原型模式主要面对的问题是:“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。
适用情况
一个复杂对象,具有自我复制功能,统一一套接口。
案例
class Person {
public:
virtual Person *Clone() = 0;
virtual void printT() = 0;
};
class JavaProgrammer : public Person {
public:
virtual Person *Clone() {
JavaProgrammer *p = new JavaProgrammer;
*p = *this;
return p;
}
结构型模式
代理模式
Proxy 模式又叫做代理模式,是构造型的设计模式之一,它可以为其他对象提供一 种代理(Proxy)以控制对这个对象的访问。
所谓代理,是指具有与代理元(被代理的对象)具有相同的接口的类,客户端必须 通过代理与被代理的目标类交互,而代理一般在交互的过程中(交互前后),进行某些 特别的处理。
类图角色和职责
- subject(抽象主题角色):
真实主题与代理主题的共同接口。 - RealSubject(真实主题角色):
定义了代理角色所代表的真实对象。 - Proxy(代理主题角色):
含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真是主题对象之前或
者之后执行某些操作,而不是单纯返回真实的对象。
适合于:
为其他对象提供一种代理以控制对这个对象的访问。
案例
using namespace std;
class Interface{
public:
virtual void Request()=0;
};
class RealClass:public Interface{
public:
virtual void Request() {
cout<<"真是的请求"<<endl;
}
};
class ProxyClass:public Interface{
PointerPropertyBuilderByName(RealClass,realClass,private)
//在该代理类中代理其他对象
virtual void Request() {
m_realClass=new RealClass();
cout<<"before call"<<endl;
m_realClass->Request();
cout<<"after call"<<endl;
delete m_realClass;
}
};
装饰模式
装饰模式又称包装模式,通过一种对客户端透明的方式来扩展对象,是继承关系的一个替换方案
角色与职责
适用于:
装饰者模式(Decorator Pattern)动态的给一个对象添加一些额外的职责。就增加功能 来说,此模式比生成子类更为灵活。
案例
class Car{
public:
virtual void show()=0;
};
class RunCar:public Car{
public:
void run() {
cout << "可以跑" << endl;
}
void show(){
run();
}
};
class SwimCarDirector : public Car {
PointerPropertyBuilderByName(Car,car,private)
public:
//这里送入被包装对象是关键
SwimCarDirector(Car *p){
this->m_car=p;
}
void swim(){
cout<<"可以游泳"<<endl;
}
// Car interface
public:
void show(){
//使用他人的功能
this->m_car->show();
//调用自己的功能。
this->swim();
}
};
class FlyCar:public Car{
PointerPropertyBuilderByName(Car,car,private)
public:
FlyCar(Car *p){
this->m_car=p;
}
void fly(){
cout<<"可以飞"<<endl;
}
// Car interface
public:
void show(){
this->m_car->show();
this->fly();
}
};
案例
ProxyClass *pc = new ProxyClass;
pc->Request();
Car *runcar = NULL;
runcar = new RunCar;
runcar->show();
//开始包装
SwimCarDirector *scd = new SwimCarDirector(runcar);
scd->show();
适配器模式
Adaptor模式也叫适配器模式,是构造型模式之一,通过Adapator模式可以改变类的对外部暴露接口
角色与职责
适用于: 是将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能
一起工作的那些类可以一起工作。
案例
//这个应该是目标接口吧
class Current18v{
public:
void use18vCurrent(){
cout<<"使用18v电压"<<endl;
}
};
class Current220v{
public:
void use220vCurrent(){
cout<<"使用220v电压"<<endl;
}
};
//继承目标接口
class Adapter:public Current18v{
PointerPropertyBuilderByName(Current220v,p220v,private)
public:
Adapter(Current220v *p220v){
this->m_p220v=p220v;
}
void use18vCurrent(){
cout<<"adapter 中使用电流"<<endl;
m_p220v->use220vCurrent();
}
};
组合模式
角色和职责
Composite 模式也叫组合模式,是构造型的设计模式之一。通过递归手段来构造树形的 对象结构,并可以通过一个对象来访问整个对象树。
Component (树形结构的节点抽象)
- 为所有的对象定义统一的接口(公共属性,行为等的定义) - 提供管理子节点对象的接口方法
- [可选]提供管理父节点对象的接口方法
Leaf (树形结构的叶节点) Component 的实现子类
Composite(树形结构的枝节点) Component 的实现子类
案例
class IFile{
public:
virtual ~IFile()=0;
virtual void display()=0;
virtual int add(IFile* file)=0;
virtual int remove(IFile* file)=0;
virtual list<IFile*>* getChild()=0;
};
class File:public IFile{
PointerPropertyBuilderByName(list<IFile*>,list,private)
PropertyBuilderByName(string,name,private)
public:
File(string name){
//文件是不允许有list的
this->m_list=NULL;
this->m_name=name;
}
~File(){
if(this->m_list!=NULL){
delete m_list;
}
}
virtual void display() {
cout<<this->m_name<<endl;
}
virtual int add(IFile *file){
return -1;
}
int remove(IFile *file){
return -1;
}
list<IFile *> *getChild(){
return NULL;
}
};
class Directory:public IFile{
PointerPropertyBuilderByName(list<IFile*>,list,private)
PropertyBuilderByName(string,name,private)
public:
Directory(string name){
this->m_name=name;
this->m_list=new list<IFile*>;
}
~Directory(){
if(m_list!=NULL){
delete this->m_list;
this->m_list=NULL;
}
}
void display(){
cout<<this->m_name;
}
int add(IFile *file){
this->m_list->push_back(file);
return 0;
}
int remove(IFile *file){
this->m_list->remove(file);
return 0;
}
list<IFile *> *getChild(){
return this->m_list;
}
};
桥接模式
概念
Bridge 模式又叫做桥接模式,是构造型的设计模式之一。Bridge 模式基于类的最小设计 原则,通过使用封装,聚合以及继承等行为来让不同的类承担不同的责任。它的主要特点是 把抽象(abstraction)与行为实现(implementation)分离开来,从而可以保持各部分的独 立性以及应对它们的功能扩展。
角色与职责
- Client
Bridge 模式的使用者 - Abstraction
抽象类接口(接口或抽象类)维护对行为实现(Implementor)的引用 - Refined Abstraction
Abstraction 子类 - Implementor
行为实现类接口 (Abstraction 接口定义了基于 - Implementor 接口的更高层次的操作)
ConcreteImplementor Implementor 子类
适用于:
桥接模式(Bridge Pattern)是将抽象部分与实现部分分离(解耦合),使它们都可以独立的变化。
车 安装 发动机 ;不同型号的车,安装不同型号的发动机
图形 填 颜色 不同形状的图形,填充上 不同的颜色
将“车 安装 发动机”这个抽象 和 实现进行分离;两个名字 就设计两个类;
将“图形 填 颜色”这个抽象 和 实现 进行分离,两个名字,就设计两个类
案例
//引擎
class Engine{
public:
virtual ~Engine();
virtual void install()=0;
};
Engine::~Engine(){
}
//引擎
//4000引擎
class Engine4000:public Engine{
public:
void install(){
cout<<"发动机4000安装"<<endl;
}
};
//4000引擎
//3500 引擎
class Engine3500:public Engine{
public:
void install(){
cout<<"发动机4000安装"<<endl;
}
};
//3500引擎
//抽象汽车,维护抽象引擎
class Car{
PointerPropertyBuilderByName(Engine,engine,protected)
public:
Car(Engine* engine);
virtual ~Car();
virtual void installEngine()=0;
};
Car::Car(Engine *engine){
this->m_engine=engine;
}
Car::~Car(){
}
//抽象汽车
//实际汽车,维护抽象引擎,实际引擎由外部引入
class BMW7:public Car{
public:
BMW7(Engine *e);
public:
void installEngine();
};
BMW7::BMW7(Engine *e):Car(e){
}
void BMW7::installEngine(){
cout<<"Bmw7:";
m_engine->install();
}
外观模式
概念
Facade模式也叫做外观模式,Facade 模式为一 组具有类似功能的类群,比如类库,子系统等等,提供一个一致的简单的界面。这个一致的 简单的界面被称作 facade。
角色与职责
Façade
为调用方, 定义简单的调用接口。
Clients
调用者。通过 Facade 接口调用提供某功能的内部类群。
Packages
功能提供者。指提供功能的类群(模块或子系统)
适用于: 为子系统中统一一套接口,让子系统更加容易使用。
案例
class SystemA{
public:
void doThing(){
cout<<"System A do..."<<endl;
}
};
class SystemB{
public:
void doThing(){
cout<<"System B do..."<<endl;
}
};
class SystemC{
public:
void doThing(){
cout<<"System C do..."<<endl;
}
};
class Facade{
PointerPropertyBuilderByName(SystemA,a,private)
PointerPropertyBuilderByName(SystemB,b,private)
PointerPropertyBuilderByName(SystemC,c,private)
public:
Facade(){
m_a=new SystemA;
m_b=new SystemB;
m_c=new SystemC;
}
~Facade(){
delete m_a;
delete m_b;
delete m_c;
}
void doThing(){
m_a->doThing();
m_b->doThing();
m_c->doThing();
}
};
享元模式 flyweight
概念
Flyweight模式也叫做享元模式,是构造型模式之一,它通过与其他类似对象共享数据减少内存占用。
其实作为Java程序员的我们,怎么理解这个模式,就是数据库连接池,一个池里面保留着一堆链接,使用到的时候,拿对应的出来用,避免资源的浪费。
角色与概念
- 抽象享元角色(Flyweight):
所有具体享元类的父类,规定一些需要实现的公共接口。 - 具体享元角色(ConcreteFlyweight|UnshareConcreteFlyweight):
抽象享元角色的具体实现类,并实现了抽象享元角色规定的方法。 - 享元工厂角色(FlyweightFactory):
负责创建和管理享元角色。可以想象是数据库连接池。
使用场景: 是以共享的方式,高效的支持大量的细粒度的对象。
说白了就是拿一个容器存一堆对象,并且按照id获取对应对象,避免对象的重复创建
案例
using namespace std;
class Person{
PropertyBuilderByName(string,name,protected)
PropertyBuilderByName(int,age,protected)
PropertyBuilderByName(int,sex,protected)
public:
Person(string name,int age,int sex):m_name(name),m_age(age),m_sex(sex){
}
};
class Teacher:public Person{
PropertyBuilderByName(string,id,private)
public:
Teacher(string id,string name,int age,int sex):Person(name,age,sex){
this->m_id=id;
}
void printT(){
cout<<"id:"<<m_id<<"\t"
<<"name:"<<m_name<<"\t"
<<"age:"<<m_age<<"\t"
<<"sex:"<<m_sex<<"\t"
<<endl;
}
};
class TeacherFactory{
private:
map<string,Teacher*> m_tpool;
public:
TeacherFactory(){
m_tpool.empty();
}
~TeacherFactory(){
while (!m_tpool.empty()) {
//因为老师是在此容器里面创建的,所以需要在容器里面进行销毁
Teacher* tmp=NULL;
map<string,Teacher*>::const_iterator it = m_tpool.begin();
tmp=it->second;
m_tpool.erase(it);
delete tmp;
}
}
/**
* @brief getTeachar 获取老师,如果数据库已经存在了,就没有必要再次创建
* @param name
* @param age
* @param sex
* @return
*/
Teacher* getTeachar(string name,int age,int sex){
stringstream ss;
ss<<name;
ss<<age;
ss<<sex;
string tmp;
ss>>tmp;
map<string,Teacher*>::iterator it = m_tpool.find(tmp);
if(it!=m_tpool.end()){
return it->second;
}else{
Teacher *t = new Teacher(tmp,name,age,sex);
m_tpool.insert(pair<string,Teacher*>(tmp,t));
}
}
};
行为型模式
模板模式(Template)
Template Method模式也叫做模板方法模式,是行为模式之一,他把具有特定步骤算法中的某些必要的处理委托让给抽象方法,通过子类继承对抽象方法的不同实现改变整个算法的行为。
应用场景
Template Method 模式一般应用在具有以下条件的应用中:
- 具有统一的操作步骤和操作过程
- 具有不同的操作细节‘
- 存在多个同样的操作步骤的应用场景,但某些具体 操作细节却各不相同
总结:
在抽象类中统一操作步骤,并规定好接口,让子类去实现接口,这样可以把每个具体子类和操作步骤耦合
角色与职责
- AbstractClass
抽象类的父类 - ConcreteClass
具体的实现子类 - templateMethod():
模板方法 - method1()与 method2():
具体步骤方法
案例
class MakeCar{
public:
virtual ~MakeCar(){
}
virtual void makeHead()=0;
virtual void makeBody()=0;
virtual void makeTail()=0;
public:
void make(){
//一些统一的操作步骤
makeHead();
makeBody();
makeTail();
}
};
class Bus:public MakeCar{
public:
void makeHead(){
cout<<"bus make head"<<endl;
}
void makeBody(){
cout<<"bus make body"<<endl;
}
void makeTail(){
cout<<"bus make tail"<<endl;
}
};
class Jeep:public MakeCar{
public:
void makeHead(){
cout<<"jeep make head"<<endl;
}
void makeBody(){
cout<<"jeep make body"<<endl;
}
void makeTail(){
cout<<"jeep make tail"<<endl;
}
};
命令模式
概念模式
Command 模式也叫命令模式,是行为设计模式的一种,Command 模式通过被称为 Command 的类封装了对目标对象的调用行为以及调用参数。
在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建 目标对象实例;设置调用参数;调用目标对象的方法。
但在有些情况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门 的类称作 command 类。
整个调用过程比较繁杂,或者存在多处这种调用。这时,使用 Command 类对该调用加 以封装,便于功能的再利用。-
调用前后需要对调用参数进行某些处理。调用前后需要进行某些额外处理,比如日志, 缓存,记录历史操作等。
角色与职责
- Command
Command 命令的抽象类。 - ConcreteCommand
Command 的具体实现类。 - Receiver
需要被调用的目标对象。 - Invorker
通过 Invorker 执行 Command 对象。
适用于: 是将一个请求封装为一个对象,从而使你可用不同的请求对客户端进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作
class Vendor{
public:
void sailbanana(){
cout<<"卖香蕉"<<endl;
}
void sailapple(){
cout<<"卖苹果"<<endl;
}
};
class Command{
public:
virtual void sail()=0;
};
class BananaCommand:public Command{
PointerPropertyBuilderByName(Vendor,v,private)
public:
BananaCommand(Vendor* v){
this->m_v=v;
}
void sail(){
m_v->sailbanana();
}
};
class AppleCommand:public Command{
PointerPropertyBuilderByName(Vendor,v,private)
public:
AppleCommand(Vendor* v){
this->m_v=v;
}
void sail(){
m_v->sailapple();
}
};
class Waiter{
PointerPropertyBuilderByName(Command,command,private)
public:
void sail(){
m_command->sail();
}
};
int main(int argc, char *argv[])
{
Vendor *v = new Vendor;
AppleCommand *ac = new AppleCommand(v);
BananaCommand *bc = new BananaCommand(v);
Waiter *wt = new Waiter();
wt->setcommand(ac);
wt->setcommand(bc);
wt->sail();
return 0;
}
责任链模式
Chain of Responsibility(CoR)模式也叫职责链模式或者职责连锁模式,是行为模式之一,该模式构造一系列分别担当不同的职责的类的对象来共同完成一个任务,这些类的对象之间像链条一样紧密相连。
例 1:比如客户 Client 要完成一个任务,这个任务包括 a,b,c,d 四个部分。
首先客户 Client 把任务交给 A,A 完成 a 部分之后,把任务交给 B,B 完成 b 部分,…, 直到D完成d部分
例 2:比如政府部分的某项工作,县政府先完成自己能处理的部分,不能处理的部分交 给省政府,省政府再完成自己职责范围内的部分,不能处理的部分交给中央政府,中央政府 最后完成该项工作。
例 3:软件窗口的消息传播。
例 4:SERVLET 容器的过滤器(Filter)框架实现。
角色与职责
Handler
处理类的抽象父类。
concreteHandler
具体的处理类。
责任链的优缺点
优点:
1.责任的分担,每个类只要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围
2.可以根据需要自由组合工作流程。如工作流程发生变化,可以通过重新分配对象链便可 适应新的工作流程。
3.类与类之间可以以松耦合的形式加以组织。
缺点:
因为处理时以链的形式在对象间传递消息,根据实现方式不同,有可能会影响处理的速 度。
适用于: 链条式处理事情。工作流程化、消息处理流程化、事物流程化;
案例
class CarHandle{
PointerPropertyBuilderByName(CarHandle,carhandle,protected)
public:
virtual void HandleCar()=0;
public:
//接口实现类必须的一个对象,下一个责任链
CarHandle *setNextHandle(CarHandle* carhandle){
this->m_carhandle=carhandle;
}
};
class CarHandleHead:public CarHandle{
public:
void HandleCar(){
cout<<"处理车头"<<endl;
if(this->m_carhandle!=NULL){
m_carhandle->HandleCar();
}
}
};
class CarHandleBody:public CarHandle{
public:
void HandleCar(){
cout<<"处理车身"<<endl;
if(this->m_carhandle!=NULL){
m_carhandle->HandleCar();
}
}
};
class CarHandleTail:public CarHandle{
public:
void HandleCar(){
cout<<"处理车尾"<<endl;
if(this->m_carhandle!=NULL){
m_carhandle->HandleCar();
}
}
};
int main_car()
{
CarHandleHead *chead = new CarHandleHead;
CarHandleBody *cbody = new CarHandleBody;
CarHandleTail *ctail = new CarHandleTail;
chead->setNextHandle(cbody);
cbody->setNextHandle(ctail);
ctail->setNextHandle(NULL);
chead->HandleCar();
delete ctail;
delete cbody;
delete chead;
return 0;
}
策略模式
概念
Strategy模式也叫策略模式,是行为模式之一。他对一些列算法加以封装,为所有算法 定义一个抽象的算法接口。并通过继承该抽象算法接口对所有的算法加以封装和实现,具体 的算法选择交由客户端决定(策略)。Strategy 模式主要用来平滑地处理算法的切换 。
这个设计模式,我有自己的见解哈,对于网络传输协议。我们通常会有很多混淆的方法,对于不同混淆的代码,其逻辑是各不相同的,但是其要作用的对象是一样的,所以,我们就得应用策略模式来处理这种情况。
角色和职责
Strategy
策略(算法)抽象。
ConcreteStrategy
各种策略(算法)的具体实现。
Context
策略外部封装类,或者策略的容器,根据不同策略执行不同的行为。策略由外部 环境决定。
适用于:
准备一组算法,并将每一个算法封装起来,使得它们可以互换。
策略模式的优缺点
它的优点有:
- 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。 恰当使用继承可以把公共的代码移到父类里面,从而避免重复的代码。
- 策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用 策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的 算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用 哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立 演化。继承使得动态改变算法或行为变得不可能。
- 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一 种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语 句里面,比使用继承的办法还要原始和落后。
缺点:
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须 理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道 所有的算法或行为的情况。
- 策略模式造成很多的策略类。有时候可以通过把依赖于环境的状态保存到客户端里面, 而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享 元模式来减少对象的数量。
案例
class Strategy{
public:
virtual void symEncrypt()=0;
};
class Des:public Strategy{
public:
virtual void symEncrypt(){
cout<<"Des 加密"<<endl;
}
};
class AES:public Strategy{
public:
virtual void symEncrypt() {
cout<<"Aes 加密"<<endl;
}
};
class Context{
PointerPropertyBuilderByName(Strategy,starategy,private)
public:
Context(Strategy *strategy){
this->m_starategy=strategy;
}
void Operator(){
this->m_starategy->symEncrypt();
}
};
int main(int argc, char *argv[])
{
Strategy* stra= new AES;
Context *ctx = new Context(stra);
ctx->Operator();
return 0;
}
中介模式 mediator
概念
Mediator 模式也叫中介者模式,是由 GoF 提出的 23 种软件设计模式的一种。Mediator 模式是行为模式之一,在 Mediator 模式中,类之间的交互行为被统一放在 Mediator 的对象 中,对象通过 Mediator 对象同其他对象交互,Mediator 对象起着控制器的作用。
角色和职责
模式优点
- 将系统按功能分割成更小的对象,符合类的最小设计原则
- 对关联对象的集中控制
- 减小类的耦合程度,明确类之间的相互关系:当类之间的关系过于复杂时,其中任何一 个类的修改都会影响到其他类,不符合类的设计的开闭原则 ,而 Mediator 模式将原来相互 依存的多对多的类之间的关系简化为 Mediator 控制类与其他关联类的一对多的关系,当其 中一个类修改时,可以对其他关联类不产生影响(即使有修改,也集中在 Mediator 控制类)。
- 有利于提高类的重用性
案例
using namespace std;
class Mediator;
class Person{
PropertyBuilderByName(string,name,private)
PropertyBuilderByName(int,sex,private)
PropertyBuilderByName(int,condition,private)
PointerPropertyBuilderByName(Mediator,m,private)
public:
Person(string name,int sex,int condition):m_name(name),m_sex(sex),m_condition(condition){
}
virtual void getParter(Person *p) = 0;
};
class Mediator{
PointerPropertyBuilderByName(Person,man,private)
PointerPropertyBuilderByName(Person,woman,private)
public:
Mediator(){
this->m_man=NULL;
this->m_woman=NULL;
}
void Partner(){
if(m_man->getsex()==m_woman->getsex()){
cout<<"我不是同性恋"<<endl;
}
if(m_man->getcondition()==m_woman->getcondition()){
cout << m_man->getname() << " 和 " << m_woman->getname() << "绝配" << endl;
}else{
cout << m_man->getname() << " 和 " << m_woman->getname() << "不配" << endl;
}
}
};
//中介与人的关系,你中有我父,我有你
class Woman:public Person{
PointerPropertyBuilderByName(Mediator,m,private)
public:
Woman(string name,int sex,int condition,Mediator *m):m_m(m),Person(name,sex,condition){
//
}
public:
void getParter(Person *p){
this->getm()->setwoman(this);
this->getm()->setman(p);
this->getm()->Partner();
}
};
class Man:public Person{
PointerPropertyBuilderByName(Mediator,m,private)
public:
Man(string name,int sex,int condition,Mediator *m):m_m(m),Person(name,sex,condition){
//
}
public:
void getParter(Person *p){
this->getm()->setman(this);
this->getm()->setwoman(p);
this->getm()->Partner();
}
};
观察者模式
概念
Observer 模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其 他关联对象,自动刷新对象状态。
Observer 模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保 持状态同步。
角色与职责
- Subject(被观察者)
被观察的对象,当需要被观察的状态发生变化,需要通知列表中所有的对象,Subject需要维持新增删除通知,一个观察对象列表 - ConcreteSubject
被观察者的具体实现,包含一些基本的属性状态及其他操作。 - Observer观察者
接口或抽象类,当Subject的状态发生变化的时候,Observer对象将通过一个callback函数得到通知。 - ConcreteObserver
观察者的具体实现,得到通知后完成一些具体操作
典型应用
- 侦听事件驱动程序设计中的外部事件
- 侦听/监视某个对象的状态变化
- 发布者/订阅者(publisher/subscriber)模型中,当一个外部事件(新的产品,消息的出现等 等)被触发时,通知邮件列表中的订阅者
适用于:
定义对象间一种一对多的依赖关系,使得每一个对象改变状态,则所有依赖于他们的 对象都会得到通知。
class PlayObserver{
PropertyBuilderByName(string,name,private)
PointerPropertyBuilderByName(Secretary,secretary,private)
PlayObserver(string name,Secretary* secretary):m_name(name),m_secretary(secretary){
}
public:
void udpate(string action){
cout<<"观察者受到action:"<<action<<endl;
}
};
class Secretary{
PropertyBuilderByName(string,action,private)
PointerPropertyBuilderByName(vector<PlayObserver*>,observers,private)
void addObserver(PlayObserver* observer){
this->m_observers->push_back(observer);
}
void Notify(string action){
for(vector<PlayObserver*>::iterator it=this->m_observers->begin();it!=m_observers->end();it++){
(*it)->udpate(action);
}
}
};
备忘录模式
Memento 模式也叫备忘录模式,是行为模式之一,它的作用是保存对象的内部状态,并在 需要的时候(undo/rollback)恢复对象以前的状态。
应用场景
如果一个对象需要保存状态并可通过 undo 或 rollback 等操作恢复到以前的状态时,可以使用 Memento 模式。
1)一个类需要保存它的对象的状态(相当于 Originator 角色)
2)设计一个类,该类只是用来保存上述对象的状态(相当于 Memento 角色) 3)需要的时候,Caretaker 角色要求 Originator 返回一个 Memento 并加以保存
4)undo 或 rollback 操作时,通过 Caretaker 保存的 Memento 恢复 Originator 对象的状态
角色和职责
Originator(原生者)
需要被保存状态以便恢复的那个对象。
Memento(备忘录)
该对象由 Originator 创建,主要用来保存 Originator 的内部状态。
Caretaker(管理者)
负责在适当的时间保存/恢复 Originator 对象的状态。
适用于:
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样就可以将以后的对象状态恢复到先前保存的状态。
适用于功能比较复杂的,但需要记录或维护属性历史的类;或者需要保存的属性只是
众多属性中的一小部分时 Originator 可以根据保存的 Memo 还原到前一状态。
案例
class MememTo{
PropertyBuilderByName(string,name,private)
PropertyBuilderByName(int,age,private)
public:
MememTo(string name,int age):m_name(name),m_age(age){
}
};
class Person{
PropertyBuilderByName(string,name,private)
PropertyBuilderByName(int,age,private)
public:
MememTo* createMememTo(){
return new MememTo(m_name,m_age);
}
void setMemto(MememTo *memto){
m_name=memto->getname();
m_age=memto->getage();
}
};
访问者模式
Visitor 模式也叫访问者模式,是行为模式之一,它分离对象的数据和行为,使用 Visitor 模式,可以不修改已有类的情况下,增加新的操作角色和职责。
角色与职责
抽象访问者(Visitor)角色:声明了一个或者多个访问操作,形成所有的具体元素角色必须 实现的接口。
具体访问者(ConcreteVisitor)角色:实现抽象访问者角色所声明的接口,也就是抽象访问 者所声明的各个访问操作。
抽象节点(Element)角色:声明一个接受操作,接受一个访问者对象作为一个参量。
具体节点(ConcreteElement)角色:实现了抽象元素所规定的接受操作。
结构对象(ObiectStructure)角色:有如下的一些责任,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或者一个聚集,如列(List)或集合(Set)。
适用于:
把数据结构 和 作用于数据结构上的操作 进行解耦合;
适用于数据结构比较稳定的场合
访问者模式总结:
访问者模式优点是增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者。访问者模式将有关的行为集中到一个访问者对象中。
那访问者模式的缺点是是增加新的数据结构变得困难了
优缺点
访问者模式有如下的优点:
1,访问者模式使得增加新的操作变得很容易。如果一些操作依赖于一个复杂的结构对象的 话,那么一般而言,增加新的操作会很复杂。而使用访问者模式,增加新的操作就意味着增 加一个新的访问者类,因此,变得很容易。
2,访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。
3,访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。迭代子只能 访问属于同一个类型等级结构的成员对象,而不能访问属于不同等级结构的对象。访问者模 式可以做到这一点。
4,积累状态。每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程 中将执行操作的状态积累在自己内部,而不是分散到很多的节点对象中。这是有益于系统维 护的优点。
访问者模式有如下的缺点:
1,增加新的节点类变得很困难。每增加一个新的节点都意味着要在抽象访问者角色中增加 一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作。
2,破坏封装。访问者模式要求访问者对象访问并调用每一个节点对象的操作,这隐含了一 个对所有节点对象的要求:它们必须暴露一些自己的操作和内部状态。不然,访问者的访问 就变得没有意义。由于访问者对象自己会积累访问操作所需的状态,从而使这些状态不再存 储在节点对象中,这也是破坏封装的。
案例
案例需求: 比如有一个公园,有一到多个不同的组成部分;该公园存在多个访问者:清洁工 A 负责
打扫公园的 A 部分,清洁工 B 负责打扫公园的 B 部分,公园的管理者负责检点各项事务是 否完成,上级领导可以视察公园等等。也就是说,对于同一个公园,不同的访问者有不同的 行为操作,而且访问者的种类也可能需要根据时间的推移而变化(行为的扩展性)。
根据软件设计的开闭原则(对修改关闭,对扩展开放),我们怎么样实现这种需求呢?
class ParkElement;
//不同的访问者 访问公园完成不同的动作 class Visitor
class Visitor{
public:
virtual void visit(ParkElement *park) = 0;
};
class ParkElement {
public:
virtual void accept(Visitor *v) = 0;
};
class ParkA : public ParkElement{
public:
virtual void accept(Visitor *v) {
v->visit(this);
}
};
class ParkB : public ParkElement {
public:
virtual void accept(Visitor *v) {
v->visit(this);
}
};
class Park {
public:
Park() {
m_list.clear(); }
void setPart(ParkElement *e) {
m_list.push_back(e); }
public:
void accept(Visitor *v) {
for ( list<ParkElement *>::iterator it=m_list.begin(); it != m_list.end(); it++) {
(*it)->accept(v); }
}
private:
list<ParkElement *> m_list;
};
class VisitorA : public Visitor {
public:
virtual void visit(ParkElement *park) {
cout << "清洁工 A 访问公园 A 部分,打扫卫生完毕" << endl;
}
};
class VisitorB : public Visitor {
public:
virtual void visit(ParkElement *park) {
cout << "清洁工 B 访问 公园 B 部分,打扫卫生完毕" << endl;
}
};
class VisitorManager : public Visitor {
public:
virtual void visit(ParkElement *park) {
cout << "管理员 检查整个公园卫生打扫情况" << endl;
}
};
int main() {
VisitorA *visitorA = new VisitorA;
VisitorB *visitorB = new VisitorB;
ParkA *partA = new ParkA;
ParkB *partB = new ParkB;
//公园接受访问者 a 访问
partA->accept(visitorA);
partB->accept(visitorB);
VisitorManager *visitorManager = new VisitorManager;
Park * park = new Park;
park->setPart(partA);
park->setPart(partB);
park->accept(visitorManager);
cout<<"hello..."<<endl;
system("pause") ;
return 0;
}
状态模式
State 模式也叫状态模式,是行为设计模式的一种。State 模式允许通过改变对象的内部 状态而改变对象的行为,这个对象表现得就好像修改了它的类一样。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状 态的判断逻辑转译到表现不同状态的一系列类当中,可以把复杂的判断逻辑简化。
角色和职责
Context:用户对象
拥有一个 State 类型的成员,以标识对象的当前状态;
State:接口或基类
封装与 Context 的特定状态相关的行为;
ConcreteState:接口实现类或子类 实现了一个与 Context 某个状态相关的行为。
适用于: 对象的行为,依赖于它所处的当前状态。行为随状态改变而改变的场景。
适用于:通过用户的状态来改变对象的行为。
案例
#include <iostream>
using namespace std;
class Worker;
class State
{
public:
virtual void doSomeThing(Worker *w) = 0;
};
class Worker {
public:
Worker();
int getHour() {
return m_hour;
}
void setHour(int hour) {
m_hour = hour;
}
State* getCurrentState() {
return m_currstate;
}
void setCurrentState(State* state) {
m_currstate = state;
}
void doSomeThing() //
{
m_currstate->doSomeThing(this);
}
private:
int m_hour;
State *m_currstate; //对象的当前状态
};
class State1 : public State {
public:
void doSomeThing(Worker *w); };
class State2 : public State {
public:void doSomeThing(Worker *w); };
void State1::doSomeThing(Worker *w) {
if (w->getHour() == 7 || w->getHour()==8) {
cout << "吃早饭" << endl; }
else {
delete w->getCurrentState();
w->setCurrentState(new State2 );
w->getCurrentState()->doSomeThing(w); //
}
}
void State2::doSomeThing(Worker *w) {
if (w->getHour() == 9 || w->getHour()==10) {
cout << "工作" << endl; }
else {
delete w->getCurrentState();
//状态 2 不满足 要转到状态 3 后者恢复到初始化状态
w->setCurrentState(new State1); //恢复到当初状态
cout << "当前时间点:" << w->getHour() << "未知状态" << endl;
}
}
Worker::Worker() {
m_currstate = new State1;
}
void main() {
Worker *w1 = new Worker;
w1->setHour(7);
w1->doSomeThing();
w1->setHour(9);
w1->doSomeThing();
delete w1; cout<<"hello..."<<endl;
system("pause");
return ;
}
解释模式 interpreter
概念
角色和职责
Interpret(Context I*contest)
解释器上下文环境类。用来存储解释器的上下文环境,比如需要解释的文法等。
AbstractExpression
解释器抽象类。
ConcreteExpression
解释器具体实现类。
案例
class Context {
public:
Context(int num) {
m_num = num;
}
public:
void setNum(int num) {
m_num = num;
}
int getNum() {
return m_num;
}
void setRes(int res) {
m_res = res;
}
int getRes() {
return m_res;
}
private:
int m_num;
int m_res;
};
class Expression {
public:
virtual void interpreter(Context *context) = 0;
};
class PlusExpression : public Expression {
public:
virtual void interpreter(Context *context) {
int num = context->getNum();
num ++ ; context->setNum(num);
context->setRes(num);
}
};
class MinusExpression : public Expression {
public:
virtual void interpreter(Context *context) {
int num = context->getNum();
num -- ;
context->setNum(num);
context->setRes(num);
}
};
int main() {
Context *pcxt = new Context(10);
Expression *e1 = new PlusExpression;
e1->interpreter(pcxt);
cout << "PlusExpression:" << pcxt->getRes() << endl;
Expression *e2 = new MinusExpression; e2->interpreter(pcxt);
cout << "MinusExpression:" << pcxt->getRes() << endl;
delete e2;
delete e1; system("pause");
return 1;
}
迭代器模式
Iterator 模式也叫迭代模式,是行为模式之一,它把对容器中包含的内部对象的访问委让 给外部类,使用 Iterator(遍历)按顺序进行遍历访问的设计模式。
在应用 Iterator 模式之前,首先应该明白 Iterator 模式用来解决什么问题。或者说,如 果不使用 Iterator 模式,会存在什么问题。
- 由容器自己实现顺序遍历。直接在容器类里直接添加顺序遍历方法
- 让调用者自己实现遍历。直接暴露数据细节给外部。
以上方法 1 与方法 2 都可以实现对遍历,这样有问题呢?
- 容器类承担了太多功能:一方面需要提供添加删除等本身应有的功能;一方面还需要提 供遍历访问功能。
- 往往容器在实现遍历的过程中,需要保存遍历状态,当跟元素的添加删除等功能夹杂在 一起,很容易引起混乱和程序运行错误等。
Iterator 模式就是为了有效地处理按顺序进行遍历访问的一种设计模式,简单地说, Iterator 模式提供一种有效的方法,可以屏蔽聚集对象集合的容器类的实现细节,而能对容 器内包含的对象元素按顺序进行有效的遍历访问。所以,Iterator 模式的应用场景可以归纳
为满足以下几个条件:
- 访问容器中包含的内部对象
- 按顺序访问
角色和职责
GOOD:提供一种方法顺序访问一个聚敛对象的各个元素,而又不暴露该对象的内部表 示。
为遍历不同的聚集结构提供如开始,下一个,是否结束,当前一项等统一接口。
Iterator(迭代器接口):
该接口必须定义实现迭代功能的最小定义方法集 比如提供 hasNext()和 next()方法。
ConcreteIterator(迭代器实现类):
迭代器接口 Iterator 的实现类。可以根据具体情况加以实现。
Aggregate(容器接口): 定义基本功能以及提供类似 Iterator iterator()的方法。
concreteAggregate(容器实现类): 容器接口的实现类。必须实现 Iterator iterator()方法。