上一篇介绍了创建型模式
http://blog.csdn.net/songshimvp1/article/details/48786615——单例模式、简单工厂模式,多态工厂模式、抽象工厂模式、建造者模式、原型模式(prototype),接下来介绍结构型模式——代理模式、装饰模式、适配器模式(adapter)、组合模式、桥接模式(bridge)、外观模式(facade)、享元模式(flyweight)。
真实玩家(李),代理玩家(赵);代理玩家(赵),代替(李),进行升级打怪。
如果抽象出不同的车型、不同型号的发动机,然后不同类型的车去安装不同类型的发动机,但是事实上车和发动机之间的会有交叉(多对多),如果用继承的方式,会引起子类的泛滥。所以需要把“安装发动机”这个事,做很好的分解;把 抽象 和 行为实现 分开。
再比如:图形的填充,图形有多个(矩形、正方形,圆、椭圆等),颜色也有很多种(红、橙、黄、绿等),不同的图形可以填充不同的颜色,如果用继承去实现“填充”这一动作,显然非常不合理。
上述介绍了结构型模式——代理模式、装饰模式、适配器模式(adapter)、组合模式、桥接模式(bridge)、外观模式(facade)、享元模式(flyweight)。接下来介绍行为型模式 http://blog.csdn.net/songshimvp1/article/details/48970017——模板模式(template)、命令模式(command)、责任链模式、策略模式、中介者模式(mediator)、观察者模式(observer)、备忘录模式(mememto)、访问者模式(visitor)、状态模式(state)、解释模式(interpreter)、迭代器模式(iterator)。
设计模式详解之——结构型模式
1、代理模式(Proxy)★
Proxy模式,代理模式,是构造型的设计模式之一,它可以为其他对象提供一种代理(Proxy)以控制对这个对象的访问。所谓代理,是指具有与代理元(被代理的对象)具有 相同的接口 的类,客户端必须通过 代理与被代理的目标类 交互,而代理一般在交互的过程中(交互前后)进行某些特别的处理。 适合于:为其他对象提供一种代理以控制对这个对象的访问。实现:a中包含b类;a、b类实现协议类protocol 。真实玩家(李),代理玩家(赵);代理玩家(赵),代替(李),进行升级打怪。
/*
出版社,为被代理对象,要卖书;
淘宝、当当网(网上书店),为代理对象;
客户端通过当当网进行买书;
*/
#include<iostream>
using namespace std;
class Subject //抽象层,作为真实主题(RealSubject)和代理主题(Proxy)的共同接口
{
public:
virtual void sailbook() = 0;
};
//真实主题角色:定义了代理角色所代表的真实对象
class RealSubjectBook :public Subject
{
public:
virtual void sailbook()
{
cout << "实体店卖书..." << endl;
}
};
//a中包含b类;a、b类实现协议类protocol
//代理主题角色:代理角色通常在将 客户端调用 传递给 真实对象 之前或者之后 执行某些操作,而不是单纯返回 真实对象
class dangdangProxy : public Subject
{
public:
void SetRealSubject()
{
RealSubjectBook *rs = new RealSubjectBook;
m_subject = rs;
}
virtual void sailbook()
{
SetRealSubject();
dazhe(); //执行打折操作
m_subject->sailbook();
}
void dazhe()
{
cout << "当当 双十一打折半价..." << endl;
}
private:
RealSubjectBook *m_subject;
};
void main()
{
Subject *s = new dangdangProxy;
s->sailbook();
delete s;
}
2、装饰模式(decorator)★
装饰( Decorator )模式又叫做包装模式。通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案。 装饰模式就是把要添加的附加功能分别放在单独的类中,并让这个类包含它要装饰的对象,当需要执行时,客户端就可以有选择地、按顺序地使用装饰功能包装对象。 适用于:装饰模式(Decorator Pattern)动态的给一个对象添加一些额外的职责。就增加功能来说,此模式比生成子类更为灵活。#include<iostream>
using namespace std;
class Car
{
public:
virtual void show() = 0;
};
class RunCar :public Car
{
public:
virtual void show()
{
cout << "可以跑!" << endl;
}
};
class SwimCarDirector :public Car
{
public:
SwimCarDirector(Car *car)
{
m_car = car;
}
void SwimCar()
{
cout << "可以游!" << endl;
}
virtual void show()
{
m_car->show();
SwimCar();
}
private:
Car* m_car;
};
class FlyCarDirector :public Car
{
public:
FlyCarDirector(Car *car)
{
mm_car = car;
}
void FlyCar()
{
cout << "可以飞!" << endl;
}
virtual void show()
{
mm_car->show();
FlyCar();
}
private:
Car* mm_car;
};
void main()
{
Car *mycar = NULL;
mycar = new RunCar;
cout << "初级:---" << endl;
mycar->show();
cout << endl;
cout << "升级游:---" << endl;
SwimCarDirector *myswimcar = new SwimCarDirector(mycar); //自由组合装饰类(增加的功能的单独封装)
myswimcar->show();
cout << endl;
cout << "升级飞:---" << endl;
FlyCarDirector *myflycar = new FlyCarDirector(myswimcar); //自由组合装饰类(增加的功能的单独封装)
myflycar->show();
delete mycar;
delete myflycar;
delete myswimcar;
}
3、适配器模式(adapter)★
通过Adapter模式可以改变已有类(或外部类)的接口形式。 适用于:是将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。class Current18v //希望使用电压18V
{
public:
virtual void useCurrent18v() = 0;
};
class Current220v //现有电压220V
{
public:
void useCurrent220v()
{
cout << "我是220v,欢迎使用..." << endl;
}
};
class Adapter : public Current18v //适配器:转换接口
{
public:
Adapter(Current220v *current)
{
m_current = current;
}
virtual void useCurrent18v()
{
cout << "适配器,适配 220v:——";
m_current->useCurrent220v();
}
private:
Current220v *m_current; //关联
};
void main()
{
Current220v *current220v = NULL;
Adapter *adapter = NULL;
current220v = new Current220v;
adapter = new Adapter(current220v);
adapter->useCurrent18v();//客户端通过适配器使用18V,但是在适配器内部使用220V
delete current220v;
delete adapter;
}
4、组合模式(composite)
Composite模式也叫组合模式,是构造型的设计模式之一。通过递归手段来构造树形的对象结构,并可以通过一个对象来访问整个对象树。 适用于:单个对象和组合对象的使用具有一致性。将对象组合成树形结构以表示“部分--整体”class IFile
{
public:
virtual void display() = 0;
virtual int add(IFile *ifile) = 0;
virtual int remove(IFile *ifile) = 0;
virtual list<IFile *> *getChild() = 0;
};
//文件 结点
class File : public IFile
{
public:
File(string name)
{
m_name = name;
}
virtual void display()
{
cout << m_name << endl;
}
virtual int add(IFile *ifile)
{
return -1;
}
virtual int remove(IFile *ifile)
{
return -1;
}
virtual list<IFile *> *getChild()
{
return NULL;
}
private:
string m_name;
};
//目录 结点
class Dir : public IFile
{
public:
Dir(string name)
{
m_name = name;
m_list = new list<IFile *>;
m_list->clear();
}
virtual void display()
{
cout << m_name << endl;
}
virtual int add(IFile *ifile)
{
m_list->push_back(ifile);
return 0;
}
virtual int remove(IFile *ifile)
{
m_list->remove(ifile);
return 0;
}
virtual list<IFile *> *getChild()
{
return m_list;
}
private:
string m_name;
list<IFile *> *m_list;
};
//递归的显示树
void showTree(IFile *root, int level)
{
int i = 0;
if (root == NULL)
{
return;
}
for (i = 0; i<level; i++)
{
printf("\t");
}
//1 显示根 结点
root->display();
//2 若根结点 有孩子
//判读孩子是文件,显示名字 )
//判断孩子是目录,showTree(子目录)
list<IFile *> *mylist = root->getChild();
if (mylist != NULL) //说明是一个目录
{
for (list<IFile *>::iterator it = mylist->begin(); it != mylist->end(); it++)
{
if ((*it)->getChild() == NULL)
{
for (i = 0; i <= level; i++) //注意 <=
{
printf("\t");
}
(*it)->display(); //显示叶子结点
}
else
{
showTree(*it, level + 1); //显示子目录
}
}
}
}
void main()
{
Dir *root = new Dir("C");
//root->display();
Dir *dir1 = new Dir("111dir");
File *aaafile = new File("aaa.txt");
//获取root结点下的 孩子集合
list<IFile *> *mylist = root->getChild();
root->add(dir1);
root->add(aaafile);
// (111dir) (aaa.txt)
// ▲
for (list<IFile *>::iterator it = mylist->begin(); it != mylist->end(); it++)
{
(*it)->display();
}
Dir *dir222 = new Dir("222dir");
File *bbbfile = new File("bbb.txt");
dir1->add(dir222);
dir1->add(bbbfile);
cout << "通过 showTree 方式 显示 root 结点下的 所有子结点" << endl;
showTree(root, 0);
}
5、桥接模式(bridge)★
Bridge模式基于类的最小设计原则,通过使用封装、聚合以及继承等行为来让 不同的类 承担 不同的责任。它的主要特点是 把 抽象(abstraction) 与 行为实现(implementation) 分离开来,从而可以保持 各部分的独立性 以及 对应它们的功能扩展。 适用于:桥接模式(Bridge Pattern)是将抽象部分与实现部分分离(解耦合),使它们都可以独立的变化。车 安装 发动机 ;不同型号的车,安装不同型号的发动机,将“车 安装 发动机”这个抽象 和 实现进行分离,两个名字 就设计两个类!如果抽象出不同的车型、不同型号的发动机,然后不同类型的车去安装不同类型的发动机,但是事实上车和发动机之间的会有交叉(多对多),如果用继承的方式,会引起子类的泛滥。所以需要把“安装发动机”这个事,做很好的分解;把 抽象 和 行为实现 分开。
再比如:图形的填充,图形有多个(矩形、正方形,圆、椭圆等),颜色也有很多种(红、橙、黄、绿等),不同的图形可以填充不同的颜色,如果用继承去实现“填充”这一动作,显然非常不合理。
//所以需要把“安装发动机”这个事,做很好的分解;把 抽象 和 行为实现 分开
//发动机
class Engine
{
public:
virtual void InstallEngine() = 0; //动作的真正实现在发动机完成,而动作的定义在“车”类里面
};
class Engine4400cc : public Engine
{
public:
virtual void InstallEngine()
{
cout << "我是 4400cc 发动机 安装完毕 " << endl;
}
};
class Engine4500cc : public Engine
{
public:
virtual void InstallEngine()
{
cout << "我是 4500cc 发动机,安装完毕 " << endl;
}
};
//车
class Car
{
public:
Car(Engine *engine)
{
this->m_engine = engine;
}
virtual void installEngine() = 0; //安装发动机的动作的定义
protected:
Engine *m_engine; //抽象类之间进行桥接
};
class BMW5 : public Car
{
public:
BMW5(Engine *engine) : Car(engine)
{
;
}
virtual void installEngine()
{
m_engine->InstallEngine(); //安装发动机的动作的实现——Engine
}
};
class BMW6 : public Car
{
public:
BMW6(Engine *engine) : Car(engine)
{
;
}
//注意 车的安装 和 发动机的安装 的不同之处
virtual void installEngine()
{
cout << "我是 BMW6 " << endl;
m_engine->InstallEngine(); //动作的实现
}
};
//抽象一个car基类和engine基类,客户端面向抽象基类编程
void main()
{
Engine *engine = NULL;
BMW6 *bmw6 = NULL;
engine = new Engine4400cc;
bmw6 = new BMW6(engine);
bmw6->installEngine();
delete bmw6;
delete engine;
}
6、外观模式(facade)
Facade模式为一组具有类似功能的类群,比如类库,子系统等等,提供一个一致的简单的界面。这个一致的简单的界面被称作facade。 适用于:为子系统中统一一套接口,让子系统更加容易使用。class SubSystemA
{
public:
void doThing()
{
cout << "SubSystemA run" << endl;
}
};
class SubSystemB
{
public:
void doThing()
{
cout << "SubSystemB run" << endl;
}
};
class SubSystemC
{
public:
void doThing()
{
cout << "SubSystemC run" << endl;
}
};
class Facade
{
public:
Facade()
{
sysA = new SubSystemA;
sysB = new SubSystemB;
sysC = new SubSystemC;
}
~Facade()
{
delete sysA;
delete sysB;
delete sysC;
}
public:
void doThing()
{
sysA->doThing();
sysB->doThing();
sysC->doThing();
}
private:
SubSystemA *sysA;
SubSystemB *sysB;
SubSystemC *sysC;
};
void main001() //旧的方式
{
SubSystemA *sysA = new SubSystemA;
SubSystemB *sysB = new SubSystemB;
SubSystemC *sysC = new SubSystemC;
sysA->doThing();
sysB->doThing();
sysC->doThing();
delete sysA;
delete sysB;
delete sysC;
}
void main08() //新的模式——使用外观模式
{
Facade *f = new Facade;
f->doThing();
delete f;
}
7、享元模式(flyweight)
Flyweight模式也叫享元模式,是构造型模式之一,它通过与其他类似对象共享数据来减小内存占用。使用场景:以共享的方式,高效的支持大量的细粒度的对象。class Person
{
public:
Person(string name, int age)
{
this->m_name = name;
this->age = age;
}
virtual void printT() = 0;
protected:
string m_name;
int age;
};
class Teacher : public Person
{
public:
Teacher(string name, int age, string id) : Person(name, age)
{
this->m_id = id;
}
void printT()
{
cout << "name:" << m_name << " age:" << age << " m_id:" << m_id << endl;
}
private:
string m_id;
};
//完成 老师结点 存储
class FlyWeightTeacherFactory
{
public:
FlyWeightTeacherFactory()
{
map1.clear();
}
~FlyWeightTeacherFactory() //防止内存泄露,因为每个Teacher都是new出来的
{
while (!map1.empty())
{
Person *tmp = NULL;
map<string, Person *>::iterator it = map1.begin();
tmp = it->second;
map1.erase(it); //把第一个结点 从容器中删除
delete tmp;
}
}
Person* GetTeacher(string id)
{
Person *tmp = NULL;
map<string, Person *>::iterator it;
it = map1.find(id);
if (it == map1.end()) //没有找到
{
string tmpname;
int tmpage;
cout << "\n请输入老师name:";
cin >> tmpname;
cout << "\n请输入老师 age:";
cin >> tmpage;
tmp = new Teacher(tmpname, tmpage, id);
map1.insert(pair<string, Person*>(id, tmp));
}
else
{
tmp = it->second; //Person*
}
return tmp;
}
private:
map<string, Person*> map1;
};
void main009()
{
Person *p1 = NULL;
Person *p2 = NULL;
FlyWeightTeacherFactory *fwtf = new FlyWeightTeacherFactory;
p1 = fwtf->GetTeacher("001"); //第一次获取
p1->printT();
p2 = fwtf->GetTeacher("001"); //第二次获取
p2->printT();
delete fwtf;
}
上述介绍了结构型模式——代理模式、装饰模式、适配器模式(adapter)、组合模式、桥接模式(bridge)、外观模式(facade)、享元模式(flyweight)。接下来介绍行为型模式 http://blog.csdn.net/songshimvp1/article/details/48970017——模板模式(template)、命令模式(command)、责任链模式、策略模式、中介者模式(mediator)、观察者模式(observer)、备忘录模式(mememto)、访问者模式(visitor)、状态模式(state)、解释模式(interpreter)、迭代器模式(iterator)。