设计模式——Factory

来源:互联网 发布:车饰用品大全淘宝 编辑:程序博客网 时间:2024/05/21 22:54

工厂模式(Factory Pattern)是最常用的设计模式之一。
它属于创建型模式,提供了一种很好的创建对象的方法。

首先看一个例子。

在类继承过程中,我们经常将一些类的公共接口抽象出来形成一个基类,方法用virtual关键字修饰。利用多态性,我们可以声明一个基类指针,通过指向实际的子类来实现不同的功能。

class Shape{    public:        Shape();        virtual void draw(){};};class Circle : public Shape{    public:        Circle();        void draw();};class Square : public Shape{    public:        Square();        void draw();};void Circle::draw(){    cout<<"draw a circle"<<endl;}void Square::draw(){    cout<<"draw a square"<<endl;}

我们声明了一个基类Shape,里面有一个虚方法draw,从这个基类派生出了两个子类分别为Circle和Square,他们重新实现了draw方法。我们定义一个基类指针,然后分别指向不同的对象,就可以调用不同对象的方法。

    Shape *shape;    shape = new Circle();    shape->draw();    shape = new Square();    shape->draw();

结果输出如下:

this is a constructor for Shapethis is a constructor for Circledraw a circlethis is a constructor for Shapethis is a constructor for Squaredraw a square

但是,这种方式导致的问题就是,当有多个子类继承自基类,我们每次调用子类的方法就得通过new ClassName()去创建一个子类对象,将基类指针指向它,也就是说我们得清楚地知道子类的名称,然后去显式地创建一个子类对象。当系统变得很复杂后,类命名并不具有很好的可读性和记忆性,这就使得程序扩展和维护变得不方便。
那么,怎么能解决这个问题呢?Factory Pattern。

工厂模式将创建对象这个过程封装成了一个接口,通过设置参数去实现不同对象的创建,但是创建逻辑却不需要暴露。

还是看一个具体例子。

对于上面那个Shape类的派生类,我们定义了一个工厂类ShapeFactory。为这个类定义一个创建对象的接口,接收不同的参数,返回不同类型的派生类对象。

enum shapetype{    CIRCLE,    SQUARE};class ShapeFactory{    public:        Shape *createShape(enum shapetype type);};Shape *ShapeFactory::createShape(enum shapetype type){    cout<<"createShape in ShapeFactory"<<endl;    if(type == CIRCLE)        return new Circle();    if(type == SQUARE)        return new Square();    else        return NULL;}

这样,我们就可以通过这个工厂类的createShape()方法进行不同对象的创建。

    ShapeFactory *shapefactory = new ShapeFactory();    Shape *shape1 = shapefactory->createShape(CIRCLE);    shape1->draw();    Shape *shape2 = shapefactory->createShape(SQUARE);    shape2->draw();

输出结果为:

createShape in ShapeFactorythis is a constructor for Shapethis is a constructor for Circledraw a circlecreateShape in ShapeFactorythis is a constructor for Shapethis is a constructor for Squaredraw a square

这样,就能实现方便地创建对象。

另外,还有一种情况,在父类中我们并不知道具体要实例化哪一个子类,但是在这个父类的子类中我们可以知道,因此我们就需要把实例化对象的过程推迟到子类里面实现。

还是刚才那个例子,在ShapeFactory中,我们不知道要具体进行实例化的子类的名字,但是在ShapeFactory的子类中可以知道,因此,我们把实例化的过程放到ShapeFactory的子类中去实现。

class ShapeFactory{    public:        virtual Shape *createShape(enum shapetype type);};class MyFactory : public ShapeFactory{    public:        Shape *createShape(enum shapetype type);};Shape *MyFactory::createShape(enum shapetype type){    cout<<"createShape in MyFactory"<<endl;    if(type == CIRCLE)        return new Circle();    if(type == SQUARE)        return new Square();    else        return NULL;}

我们将ShapeFactory中的createShape()方法定义为一个虚函数,然后写一个MyFactory继承自ShapeFactory,并实现了父类的创建对象方法。

    MyFactory *myfactory = new MyFactory();    Shape * shape1 = myfactory->createShape(CIRCLE);    shape1->draw();    Shape *shape2 = myfactory->createShape(SQUARE);    shape2->draw();

同样的方法,用子类去创建对象,结果输出为:

createShape in MyFactorythis is a constructor for Shapethis is a constructor for Circledraw a circlecreateShape in MyFactorythis is a constructor for Shapethis is a constructor for Squaredraw a square

对上面两种用法总结一下,也即Factory模式两个最重要的功能:

  • 定义创建对象的接口,封装创建对象的过程;
  • 将实例化类的过程延后到子类里面实现。

一些分析:

Factory模式在实际开发中应用非常广泛。
面向对象的系统经常面临着各种对象创建问题,而建的类实在是太多了。而Factory提供的创建对象的接口封装和推迟类的实例化过程很好地解决了部分问题。它屏蔽了创建对象过程的具体实现,只提供一个对外接口,只需要知道对应参数就可以进行对象创建,而且扩展也很方便,只需要扩展工厂类就可以了。

但是,Factory模式也会带来一些问题。
当我们需要创建一个新类型的对象时,需要扩展工厂类,这就使得工厂类接口永远不能封闭。当然可以通过创建工厂类的子类通过多态来实现,但是这又引入了一个新的类,增加了系统的复杂性。

扩展:
Factory模式为开发者提供了很好的对象创建的实现策略,但是它仅仅局限于一个类族,也即这些创建对象的子类拥有一个共同的基类,当我们要实现为不同类提供对象创建接口时,就需要用到 AbstractFactory模式了。


本文的例子:https://github.com/ilovechocolate/Design-Patterns.git

原创粉丝点击