- 结构型模式,共七种:
- 外观(门面)模式
- 外观模式应该是
用的很多
的一种模式,特别是当一个系统很复杂时,系统提供给客户的是一个简单的对外接口,而把里面复杂的结构都封装了起来。隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。属于结构型模式。这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。
#include<iostream> using namespace std; //创建一个形状的抽象接口shape class shape { public: shape() {}; virtual ~shape() {}; virtual void draw()=0; }; //创建实现形状抽象接口的实体类rectangle class rectangle :public shape { public: rectangle() {}; ~rectangle() {}; void draw(); }; void rectangle::draw() { cout << "rectangle::draw()" << endl; } //创建实现形状抽象接口的实体类square class square :public shape { public: square() {}; ~square() {}; void draw(); }; void square::draw() { cout << "square::draw()" << endl; } //创建实现形状抽象接口的实体类circle class circle :public shape { public: circle() {}; ~circle() {}; void draw(); }; void circle::draw() { cout << "circle::draw()" << endl; } //创建一个外观类。隐藏系统的复杂性,提供访问系统的接口 class shapemaker { public: shapemaker(); ~shapemaker(); void drawcircle(); void drawrectangle(); void drawsquare(); private: shape *circlet; shape *rectanglet; shape *squaret; }; shapemaker::shapemaker() { circlet = (shape*)new circle(); rectanglet = (shape*)new rectangle(); squaret = (shape*)new square(); } shapemaker::~shapemaker() { delete circlet; circlet = NULL; delete rectanglet; rectanglet = NULL; delete squaret; squaret = NULL; } void shapemaker::drawcircle() { circlet->draw(); } void shapemaker::drawrectangle() { rectanglet->draw(); } void shapemaker::drawsquare() { squaret->draw(); } int main() { shapemaker *shapemakert = new shapemaker(); shapemakert->drawcircle(); shapemakert->drawrectangle(); shapemakert->drawsquare(); delete shapemakert; shapemakert = NULL; system("pause"); return 0; }
- 外观模式应该是
- 组合模式
- 将对象组合成
树形结构
以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。它能够使客户端在操作整体对象或者其下的每个节点对象时做出统一的响应,保证树形结构对象使用方法的一致性,使客户端不必关注对象的整体或部分,最终达到对象复杂的层次结构与客户端解耦的目的。
#include<iostream> #include<string> #include<list> using namespace std; //创建Employee类,该类带有Employee对象的列表。 class employee { public: employee(string tname, string tdept, int tsalary) { name = tname; dept = tdept; salary = tsalary; }; ~employee() {}; void add(employee e) { subordinates.push_back(e); }; void remove(employee e) { subordinates.remove(e); }; string get_name() { return name; }; string get_dept() {return dept;}; int get_salary() { return salary; }; list<employee> get_subordinates() { return subordinates; }; void toString() { cout << "name: " << name << endl << "dept: " << dept << endl << "salary: " << salary << endl; }; friend bool operator==(const employee &a, const employee &b); private: string name; string dept; int salary; list<employee> subordinates; }; bool operator==(const employee &a, const employee &b) { if (a.name == b.name && a.dept == b.dept) { return true; } else { return false; } } int main() { employee t1("Jhon", "CEO", 30000); employee t2("Robert", "Sales", 10000); employee t3("Michel", "Support", 10000); employee t4("Luara", "Market", 10000); employee t5("Bob", "Technique", 15000); t1.add(t2); t1.add(t3); t1.add(t4); t1.add(t5); t1.toString(); cout << endl; list<employee> iy = t1.get_subordinates(); list<employee>::iterator it; for (it = iy.begin(); it != iy.end(); ++it) { (*it).toString(); cout << endl; } return 0; }
- 将对象组合成
- 装饰器模式
- 装饰器模式(Decorator)能够在运行时动态地为原始对象增加一些额外的功能,使其变得更加强大。从某种程度上讲,装饰器非常类似于“继承”,它们都是为了增强原始对象的功能,区别在于方式的不同,后者是在编译时(compile-time)静态地通过对原始类的继承完成,而前者则是在程序运行时(run-time)通过对原始对象动态地“包装”完成,是对类实例(对象)“装饰”的结果。
- 在不改变现有类的基础上添加新的功能,属于结构型设计模式,作为现有类的一个包装。 动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。有时我们希望
给某个对象
而不是整个类
添加一些功能。比如有一个手机,允许你为手机添加特性,比如增加挂件、屏幕贴膜等。一种灵活的设计方式是,将手机嵌入到另一对象中,由这个对象完成特性的添加,我们称这个嵌入的对象为装饰。这个装饰与它所装饰的组件接口一致,因此它对使用该组件的客户透明。
//公共抽象类 class Phone { public: Phone() {} virtual ~Phone() {} virtual void ShowDecorate() {} }; //具体的手机类 class iPhone : public Phone { private: string m_name; //手机名称 public: iPhone(string name): m_name(name){} ~iPhone() {} void ShowDecorate() { cout<<m_name<<"的装饰"<<endl;} }; //具体的手机类 class NokiaPhone : public Phone { private: string m_name; public: NokiaPhone(string name): m_name(name){} ~NokiaPhone() {} void ShowDecorate() { cout<<m_name<<"的装饰"<<endl;} }; //装饰类 class DecoratorPhone : public Phone { private: Phone *m_phone; //要装饰的手机 public: DecoratorPhone(Phone *phone): m_phone(phone) {} virtual void ShowDecorate() { m_phone->ShowDecorate(); } }; //具体的装饰类 class DecoratorPhoneA : public DecoratorPhone { public: DecoratorPhoneA(Phone *phone) : DecoratorPhone(phone) {} void ShowDecorate() { DecoratorPhone::ShowDecorate(); AddDecorate(); } private: void AddDecorate() { cout<<"增加挂件"<<endl; } //增加的装饰 }; //具体的装饰类 class DecoratorPhoneB : public DecoratorPhone { public: DecoratorPhoneB(Phone *phone) : DecoratorPhone(phone) {} void ShowDecorate() { DecoratorPhone::ShowDecorate(); AddDecorate(); } private: void AddDecorate() { cout<<"屏幕贴膜"<<endl; } //增加的装饰 }; int main() { Phone *iphone = new NokiaPhone("6300"); Phone *dpa = new DecoratorPhoneA(iphone); //装饰,增加挂件 Phone *dpb = new DecoratorPhoneB(dpa); //装饰,屏幕贴膜 dpb->ShowDecorate(); delete dpa; delete dpb; delete iphone; return 0; }
- 适配器模式
- 适配器模式(Adapter)通常也被称为转换器,顾名思义,它一定是进行适应与匹配工作的物件。当一个对象或类的接口不能匹配用户所期待的接口时,适配器就充当中间转换的角色,以达到兼容用户接口的目的,同时适配器也实现了客户端与接口的解耦,提高了组件的可复用性。作为两个不兼容接口之间的桥梁,结合了两个独立接口的功能,处于结构型模式在下列三种情景下可以使用适配器模式:
- 使用一个已存在的类,但其接口不符合要求
- 创建一个复用的类,该类可以与其他不相关的类或不可预见的类协同工作
- 使用一个已存在的子类,但不能对每一都进行子类化以匹配它们的接对象适配器可以适配它的父类接口。
- 在STL中就用到了适配器模式。STL实现了一种数据结构,称为双端队列(deque),支持前后两段的插入与删除。STL实现栈和队列时,没有从头开始定义它们,而是直接使用双端队列实现的。这里双端队列就扮演了适配器的角色。队列用到了它的后端插入,前端删除。而栈用到了它的后端插入,后端删除。假设栈和队列都是一种顺序容器,有两种操作:压入和弹出。
//双端队列 class Deque { public: void push_back(int x) { cout<<"Deque push_back"<<endl; } void push_front(int x) { cout<<"Deque push_front"<<endl; } void pop_back() { cout<<"Deque pop_back"<<endl; } void pop_front() { cout<<"Deque pop_front"<<endl; } }; //顺序容器 class Sequence { public: virtual void push(int x) = 0; virtual void pop() = 0; }; //栈 class Stack: public Sequence { public: void push(int x) { deque.push_back(x); } void pop() { deque.pop_back(); } private: Deque deque; //双端队列 }; //队列 class Queue: public Sequence { public: void push(int x) { deque.push_back(x); } void pop() { deque.pop_front(); } private: Deque deque; //双端队列 };
- 享元模式
- 享元模式的英文flyweight是轻量级的意思,这就意味着享元模式能使程序变得更加轻量化。当系统存在大量的对象,并且这些对象又具有相同的内部状态时,我们就可以用享元模式共享相同的元件对象,以避免对象泛滥造成资源浪费。享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。属于结构型模式。
- 享元模式。其定义为:运用共享技术有效地支持大量细粒度的对象。
- 在围棋中,棋子就是大量细粒度的对象。其属性有内在的,比如颜色、形状等,也有外在的,比如在棋盘上的位置。内在的属性是可以共享的,区分在于外在属性。因此,可以这样设计,只需定义两个棋子的对象,一颗黑棋和一颗白棋,这两个对象含棋子的内在属性;棋子的外在属性,即在棋盘上的位置可以提取出来,存放在单独的容器中。相比之前的方案,现在容器中仅仅存放了位置属性,而原来则是棋子对象。显然,现在的方案大大减少了对于空间的需求。
关注PieceBoard 的容器,之前是vector<Piece*> m_vecPiece,现在是vector m_vecPos。这里是关键。
class PieceBoard { private: vector<PiecePos> m_vecPos; //存放棋子的位置 Piece *m_blackPiece; //黑棋棋子 Piece *m_whitePiece; //白棋棋子 string m_blackName; string m_whiteName; public: PieceBoard(string black, string white): m_blackName(black), m_whiteName(white) { m_blackPiece = NULL; m_whitePiece = NULL; } ~PieceBoard() { delete m_blackPiece; delete m_whitePiece;} void SetPiece(PieceColor color, PiecePos pos) { if(color == BLACK) { if(m_blackPiece == NULL) //只有一颗黑棋 m_blackPiece = new BlackPiece(color); cout<<m_blackName<<"在位置("<<pos.x<<','<<pos.y<<")"; m_blackPiece->Draw(); } else { if(m_whitePiece == NULL) m_whitePiece = new WhitePiece(color); cout<<m_whiteName<<"在位置("<<pos.x<<','<<pos.y<<")"; m_whitePiece->Draw(); } m_vecPos.push_back(pos); } };
- 代理模式
- 代理模式(Proxy),顾名思义,有代表打理的意思。某些情况下,当客户端不能或不适合直接访问目标业务对象时,业务对象可以通过代理把自己的业务托管起来,使客户端间接地通过代理进行业务访问。如此不但能方便用户使用,还能对客户端的访问进行一定的控制。简单来说,就是代理方以业务对象的名义,代理了它的业务,为其他对象提供一种代理以控制对这个对象的访问。有四种常用的情况:(1)远程代理,(2)虚代理,(3)保护代理,(4)智能引用。
#include<iostream> #include<string> using namespace std; //创建一个图片image基类接口 class image { public: image() {}; virtual ~image() {}; virtual void display()=0; }; //创建实现image接口的实体类RealImage class RealImage :public image { public: RealImage(string tfilename); ~RealImage() {}; void display(); private: string filename; void loadFromDisk(string filename); }; RealImage::RealImage(string tfilename) { this->filename = tfilename; loadFromDisk(filename); } void RealImage::display() { cout << "RealImage:display: " <<filename<< endl; } void RealImage::loadFromDisk(string filename) { cout << "loadFromDisk: " << filename << endl; } //创建实现image接口的代理类ProxyImage class ProxyImage :public image { public: ProxyImage(string tfilename); ~ProxyImage(); void display(); private: RealImage *realimage; //包含image实体类成员变量 string filename; }; ProxyImage::ProxyImage(string tfilename) { this->filename = tfilename; realimage = NULL; } ProxyImage::~ProxyImage() { delete realimage; realimage = NULL; } void ProxyImage::display() { if (NULL == realimage) { realimage = new RealImage(filename); } realimage->display(); } int main() { image *t1 = (image*)new ProxyImage("test10.jpg"); t1->display(); cout << endl; t1->display(); delete t1; t1 = NULL; system("pause"); return 0; }
- 桥接模式
- 桥接模式(Bridge)能将抽象与实现分离,使二者可以各自单独变化而不受对方约束,使用时再将它们组合起来,就像架设桥梁一样连接它们的功能,如此降低了抽象与实现这两个可变维度的耦合度,以保证系统的可扩展性。桥接模式构架了一种分化的结构模型,巧妙地将抽象与实现解耦,分离出了2个维度(尺子与画笔)并允许其各自延伸和扩展,最终使系统更加松散、灵活
//操作系统 class OS { public: virtual void InstallOS_Imp() {} }; class WindowOS: public OS { public: void InstallOS_Imp() { cout<<"安装Window操作系统"<<endl; } }; class LinuxOS: public OS { public: void InstallOS_Imp() { cout<<"安装Linux操作系统"<<endl; } }; class UnixOS: public OS { public: void InstallOS_Imp() { cout<<"安装Unix操作系统"<<endl; } }; //计算机 class Computer { public: virtual void InstallOS(OS *os) {} }; class DellComputer: public Computer { public: void InstallOS(OS *os) { os->InstallOS_Imp(); } }; class AppleComputer: public Computer { public: void InstallOS(OS *os) { os->InstallOS_Imp(); } }; class HPComputer: public Computer { public: void InstallOS(OS *os) { os->InstallOS_Imp(); } }; int main() { OS *os1 = new WindowOS(); OS *os2 = new LinuxOS(); Computer *computer1 = new AppleComputer(); computer1->InstallOS(os1); computer1->InstallOS(os2); }
- 外观(门面)模式