设计模式一直是面向对象软件设计中最重要的一个领域,围绕设计模式讨论的话题也是数不胜数,其中GOF代表的23种设计模式更是经典之著。这个系列中我将会从自己的理解出发,阐述每种设计模式的思想,作用和利弊。
一、 设计模式概念
要讲解设计模式,必然先要说清楚两个问题,
1.什么是设计模式?
2.为什么需要设计模式?
对于设计模式,GOF是这么定义的:设计模式是对被用来在特定场景下解决一般设计问题的类和相互通信的对象的描述,更特殊地,将之放到面向对象软件设计中来讲,设计模式可以被认为是实践中总结出的设计经验,是系统中会重复出现的设计。
所以设计模式可以帮助我们更加简单方便地复用成功的设计和体系结构,更具体地,为了获得最大限度地复用的关键在于新需求和已有需求发生变化时,系统设计有能力相应地改进,避免重新设计带来的巨大代价。每种设计模式都是通过确保系统以某种特定方式变化来获得这种可变能力,每一个设计模式允许系统结构的某个方面独立于其他方面,从而对某一种特殊变化具有适应性。
这就引出了选择设计模式的方法:首先考虑系统在哪些方面具有可变性,选择的设计模式不会因为这些可变因素而引起重新设计。GOF根据设计模式完成的任务类型将其分为了创建型,结构型和行为型三大类,创建型模式用于对象的创建,结构型模式用于处理类或者对象的组合;行为型模式描述类或对象怎样交互和分配职责。同时根据范围模式分为类模式和对象模式,类模式处理类和子类之间的关系,通过继承创建,是静态的,编译期就确定了;对象模式处理对象之间的关系,是动态的,运行时可变,具体分类如表格所示:
创建型 |
结构型 |
行为型 |
|
类模式 |
Factory method |
Adapter |
Interpreter template method |
对象模式 |
Abstract factory builder prototype singleton |
Adapter bridge composite decorator facade flyweight proxy |
Chain of responsibility command iterator mediator memento observer state strategy visitor |
创建型类模式将对象的部分创建工作延迟到子类,创建型对象模式则延迟到另一个对象中。结构型类模式使用继承机制来组合类,结构型对象模式则描述了对象的组合方式。行为类模式用继承描述算法和控制流,行为型对象模式则通过一组对象协作完成任务。另外我们将会看到,在部分类模式中,通过引入参数或者模板类型可以避免创建子类。
本系列以创建型模式的factory method模式开始,逐个介绍GOF的23种设计模式。
二、 factory method模式
如果一个类不知道需要创建的对象的类型时,如果当前希望子类来指定创建的对象类型时,如果希望将创建对象的职责委托给子类并将这一代理过程局部化时,就可以考虑使用factory method模式。
下面以一个例子来说明,这个例子也会在后续设计模式中多次提到,所以请读者先记住一下。现在要开发一个芯片设计的软件,可以在掩模上设计不同的图形。不同的掩模会有不同的参数,比如曝光方式,角度等,图形也可以会有很多种,在不影响理解的前提下我们假设只有圆形,矩形和三角形三种图形,在不同的掩模上画同一个图得到的效果是不一样的。对于同一种掩模,我们要得到一个可以画图的对象,至于画出的是圆形,矩形还是三角形,子类才能知道,掩模只能拿到接口。类设计图如下:
具体代码实现如下:
//mask.hpp #ifndef MASK_HPP #define MASK_HPP class MaskFigure{ public: virtual ~MaskFigure()=0; protected: MaskFigure(); }; class MaskRound:public MaskFigure { public: MaskRound(); ~MaskRound(); }; class MaskRec:public MaskFigure { public: MaskRec(); ~MaskRec(); }; class MaskTri:public MaskFigure { public: MaskTri(); ~MaskTri(); }; #endif //mask.cpp #include <iostream> #include "mask.hpp" using std::cout; using std::endl; MaskFigure::MaskFigure() { } MaskFigure::~MaskFigure() { } MaskRound::MaskRound() { cout<<"Draw roundness on Mask"<<endl; } MaskRound::~MaskRound() { } MaskRec::MaskRec() { cout<<"Draw rectangle on Mask"<<endl; } MaskRec::~MaskRec() { } MaskTri::MaskTri() { cout<<"Draw triangle on Mask"<<endl; } MaskTri::~MaskTri() { } //factory.hpp #ifndef MASKFACTORY_HPP #define MASKFACTORY_HPP #include "mask.hpp" class FigureFactory { public: virtual ~FigureFactory()=0; virtual MaskFigure* CreateFigure()=0; protected: FigureFactory(); }; class RoundFactory:public FigureFactory { public: RoundFactory(); ~RoundFactory(); MaskRound* CreateFigure(); }; class RecFactory:public FigureFactory { public: RecFactory(); ~RecFactory(); MaskRec* CreateFigure(); }; class TriFactory:public FigureFactory { public: TriFactory(); ~TriFactory(); MaskTri* CreateFigure(); }; #endif //factory.cpp #include <iostream> #include "factory.hpp" using std::cout; using std::endl; FigureFactory::FigureFactory() { } FigureFactory::~FigureFactory() { } RoundFactory::RoundFactory() { cout<<"Init RoundFactory"<<endl; } RoundFactory::~RoundFactory() { } MaskRound* RoundFactory::CreateFigure() { return new MaskRound(); } RecFactory::RecFactory() { cout<<"Init RecFactory"<<endl; } RecFactory::~RecFactory() { } MaskRec* RecFactory::CreateFigure() { return new MaskRec(); } TriFactory::TriFactory() { cout<<"Init TriFactory"<<endl; } TriFactory::~TriFactory() { } MaskTri* TriFactory::CreateFigure() { return new MaskTri(); } //main.cc #include <memory> #include <iostream> #include "factory.hpp" #include "factorytml.hpp" using std::shared_ptr; int main() { shared_ptr<RoundFactory> roundfac(new RoundFactory()); shared_ptr<MaskRound> mrd(roundfac->CreateFigure()); shared_ptr<RecFactory> recfac(new RecFactory()); shared_ptr<MaskRec> mrc(recfac->CreateFigure()); shared_ptr<TriFactory> trifac(new TriFactory()); shared_ptr<MaskTri> mti(trifac->CreateFigure()); return 0; }
roundness, rectangle和 triangle的构造都分别延迟到了 RoundFactory, RecFactory和TriFactory等派生类中完成,所以factory method模式又被成为虚构造函数。
不难发现,MaskFigure有几个子类, FigureFactory也需要对应数目的子类,MaskFigure增加一个图形时,FigureFactory就必须增加相应的工厂方法,有时候会产生太多子类,不易维护,c++中可以引入模板或者参数化来解决,从而避免创建子类。一个模板实现的factory method实例如下:
//factorytml.hpp #ifndef FACTORYTML_HPP #define FACTORYTML_HPP #include <iostream> using std::cout; using std::endl; class FigureFactoryTml { public: FigureFactoryTml(){ cout<<"Init FigureFactoryTml"<<endl; } ~FigureFactoryTml(){ } template<typename T> T* CreateFigure() { return new T(); } }; #endif //main.cc … shared_ptr<FigureFactoryTml> fft(new FigureFactoryTml()); shared_ptr<MaskRound> mrdp(fft->CreateFigure<MaskRound>()); shared_ptr<MaskRec> mrcp(fft->CreateFigure<MaskRec>()); shared_ptr<MaskTri> mtip(fft->CreateFigure<MaskTri>()); …
(完)