C++设计模式-外观模式详解
外观模式:要求一个子系统与外部通信必须通过一个同一的系统完成,也就是把一系列的子系统封装在一个同一的大系统中。子系统中的所有调用行为都是通过大系统提供同一的接口来完成。 在一个绘图系统中,需要绘制各种这样的图形,比如说是矩形、圆形、直线等。那好我们就根据以上场景搭建一个简单的绘制场景。首先把各种绘制的图形定义出来。 矩形: //矩形 class MyRectangle { public: MyRectangle(int w,int h); void draw(); private: int _width,_height; }; MyRectangle::MyRectangle(int w,int h) { _width = w; _height = h; } void MyRectangle::draw() { printf("绘制矩形 - 长:%d 宽:%dn",_width,_height); } 圆形: //圆 class MyCircle { public: MyCircle(int centerX,int centerY,int radio); void draw(); private: int _centerX,_centerY,_radio; }; MyCircle::MyCircle(int centerX,int radio) { _centerX = centerX; _centerY = centerY; _radio = radio; } void MyCircle::draw() { printf("绘制圆 - 圆心:(%d,%d) 半径:%dn",_centerX,_radio); } 直线: //直线 class MyLine { public: MyLine(int firstX,int firstY,int secondX,int secondY); void draw(); private: int _firstX,_firstY,_secondX,_secondY; }; MyLine::MyLine(int firstX,int secondY) { _firstX = firstX; _firstY = firstY; _secondX = secondX; _secondY = secondY; } void MyLine::draw() { printf("绘制直线 - 起点:(%d,%d),终点:(%d,%d)n",_firstX,_secondY); } 点: //点 class MyPoint { public: MyPoint(int x,int y); void draw(); private: int _x,_y; }; MyPoint::MyPoint(int x,int y) { _x = x; _y = y; } void MyPoint::draw() { printf("绘制点 - 坐标:(%d,_x,_y); } 以上需要绘制的图形已经添加完成了,下面看一下客户端是如何调用的: int main() { //绘制点 MyPoint* pt = new MyPoint(10,20); pt->draw(); //绘制直线 MyLine* l = new MyLine(30,30,90,95); l->draw(); //绘制矩形 MyRectangle* rect = new MyRectangle(150,300); rect->draw(); //绘制圆 MyCircle* circle = new MyCircle(100,100,50); circle->draw(); return 0; } 代码编写完成了,运行一下: OK,调用完成了,看到了吗? 也就是说我每次添加一个绘制的图形都要重写一遍客户端,如果添加的图形比较复杂的,或者是有很多组合图形的情况,客户端就会变得非常的臃肿,不易于维护。 那么怎么解决的?咱们把需要绘制的这个部分功能重新封装起来。需要重新定义一个类实现这个功能。 class MyDraw { public: MyDraw(); void init(); void draw(); private: MyRectangle* _myRect; MyCircle* _myCircle; MyLine* _myLine; MyPoint* _myPoint; }; MyDraw::MyDraw() { } void MyDraw::init() { _myPoint = new MyPoint(10,20); _myLine = new MyLine(30,95); _myRect = new MyRectangle(150,300); _myCircle = new MyCircle(100,50); } void MyDraw::draw() { _myPoint->draw(); _myLine->draw(); _myRect->draw(); _myCircle->draw(); } 现在把客户端的调用之后修改一下: int main() { MyDraw* myDraw = new MyDraw; myDraw->init(); myDraw->draw(); return 0; } 运行一下: 嗯哼,运行效果是一样的。 客户端只要编写很少的代码就可以实现上述的功能,也许你会说,这有什么区别嘛?只不过把我需要的功能重新封装了一下而已呀。 但是你不要忘了,如果直接使用的话,各种绘制图形就会和客户端产生一定的耦合性,如果是客户端做了修改就会影响到这部分的修改,但是如果做了封装的话就是把客户端和实际的绘制过程分开来,互不影响。 每次需要绘制的时候,只要把封装的接口直接调用就可以了。 其次,如果想要添加新的绘制图形,比如说三角形、图片等,只要在封装的类中添加行的绘制就可以了,而不用修改客户端的代码。 再次,如果这部分绘制的过程是通过DLL形式发布出去的,那么每次只要修改DLL中代码之后重新编译就可以了,和客户端没有什么关系,客户端没有修改任何代码就能实现的添加新的绘制图形。 看看咱们的代码是不是还有优化的空间? 既然会都有绘制的功能,是不是可以把绘制的过程提取出来形成基类呢? class IDraw { public: IDraw(); ~IDraw(); virtual void draw(); }; IDraw::IDraw() { } IDraw::~IDraw() { } void IDraw::draw() { } 绘制相关的类都继承这个基类: //矩形 class MyRectangle:public IDraw { public: MyRectangle(int w,int h); void draw()override; private: int _width,_height; }; //圆 class MyCircle :public IDraw { public: MyCircle(int centerX,int radio); void draw()override; private: int _centerX,_radio; }; //直线 class MyLine :public IDraw { public: MyLine(int firstX,int secondY); void draw()override; private: int _firstX,_secondY; }; //点 class MyPoint :public IDraw { public: MyPoint(int x,int y); void draw()override; private: int _x,_y; }; CPP文件保持不变,这里就不在重复了。 然后在修改一下绘制类: class MyDraw { public: MyDraw(); void init(); void draw(); private: std::vector }; MyDraw::MyDraw() { } void MyDraw::init() { _drawObjs.push_back(new MyPoint(10,20)); _drawObjs.push_back(new MyLine(30,95)); _drawObjs.push_back(new MyRectangle(150,300)); _drawObjs.push_back(new MyCircle(100,50)); } void MyDraw::draw() { int cnt = _drawObjs.size(); for (int i = 0; i < cnt;i++){ _drawObjs.at(i)->draw(); } } 这样是不是更加方便了,客户端都有不用做任何的修改! 如果要添加新的图形,只要是继承IDraw这个基类,然后在子类中完成绘制功能,把生成的子类对象,添加到_drawObjs中就可以了。绘制这部分功能就会自动的调用完成了。 外观模式优点: 1.减少了系统之间的耦合性。 2.提高灵活性。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |