C++实现Creational - Factory Method模式

来源:互联网 发布:php调用mssql存储过程 编辑:程序博客网 时间:2024/06/05 06:47

设计模式的终极原理,本质上来说就是区分变化的部分稳定的部分,并在此基础上,通过某种机制将此两者分离开来。此处所言之变化稳定均为相对概念。在实现上,稳定的部分通常以抽象的形式出现,变化的部分通常以具体的类出现。

 

Simple Factory模式中(详见http://patmusing.blog.163.com/blog/static/135834960201002323120571/ )NameSimpleFactory类是控制中枢,要创建哪个具体类的实例,是由它来控制的。Simple Factory通常具有以下的形式:

上图中,SimpleFactory类所承担的任务不够单一,一旦其中的控制逻辑发生变化,那么SimpleFactory就必须改写,这时就违背了OCP(Open-Close Principle,即开闭原则。所谓的开闭原则,简言之,就是开放扩展,关闭修改)。造成这种情况出现的原因就是因为SimpleFactory类在决定构造哪一个具体的类,因此,要解决这个问题,就必须把这部分工作分离开来,为此,可以定义一个用于创建对象的接口/抽象类,让其子类决定实例化那个类,从而使得一个类的实例化延迟到该接口/抽象类的实现类/子类。而这正是Factory Method模式的意图所在。

 

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.  - GoF

 

Factory Method又被称为Virtual Constructor,即虚拟构造器。其UML类图如下:

抽象工厂(AbstractFactory)    是工厂方法模式的核心。具体工厂必须实现在抽象工厂中定义的抽象方法。

具体工厂(ConcreteFactory)  实现抽象工厂中定义的所有抽象方法,包含与业务密切相关的逻辑。

抽象产品(AbstractProduct)    所有具体产品的超类,亦即具体产品的共同父类。

具体产品(ConcreteProduct)  这个角色实现了抽象产品角色所定义的接口。

某一具体产品通常由专门的具体工厂创建,它们之间往往一一对应,但也不尽然。

 

通过上述改造,AbstractFactory不再具有控制逻辑,到底实例化那个具体的产品类(ConcreteProduct1, 2),被延迟到了具体工厂类(ConcreteFactory1, 2)

 

我们知道:抽象类不能实例化。但这是否意味着抽象类的构造函数也是不必要的呢?请参考下面的例子:

#include<string>

#include<iostream>

usingnamespace std;

//基类

class AbstractProduct

{

protected:

        string name;                        //将被派生类继承

        double price;                      // 将被派生类继承

 

public:

        AbstractProduct(const string name, const double price)

        {

                  this->name = name;

                  this->price = price;

        }

 

        // 定义两个纯虚函数,这两个纯虚函数必须在派生类中得到实现

        virtual string get_name() const = 0;

        virtual double get_price()const = 0;

};

 

//派生类

class ConcreteProduct :public AbstractProduct

{

public:

        // 通过构造函数,向基类传递参数

        ConcreteProduct(const string name, const double price) : AbstractProduct(name, price)

        {

        }

 

        // 实现基类中的纯虚函数

        string get_name() const

        {

                  return name;

        }

 

        // 实现基类中的纯虚函数

        double get_price() const

        {

                  return price;

        }

};

 

//测试代码

int main(void)

{

        ConcreteProduct cp("笔记本电脑", 10000.1);

        cout << cp.get_name() << ": " << cp.get_price() << endl;

 

        return 0;

}

上面的代码的执行结果:

笔记本电脑: 10000.1

 

可见结果是正确的。之所以在此给出这样一个例子,是因为在一些模式的实现中,有时候需要用到类似的代码。

 

Factory Method模式的C++实现代码如下:

// FactoryMethod.h

#include<string>

#include<iostream>

#include<memory>

usingnamespace std;

 

class AbstractProduct

{

protected:

        string name;                        //将被派生类继承

        double price;                      // 将被派生类继承

 

public:

        AbstractProduct(const string name, const double price)

        {

                  this->name = name;

                  this->price = price;

        }

 

        // 定义两个纯虚函数,这两个纯虚函数必须在派生类中得到实现

        virtual string get_name() const = 0;

        virtual double get_price()const = 0;

 

        virtual ~AbstractProduct()

        {

                  cout << "This is in destructor of AbstractProduct..." << endl;

        }

};

 

class Apple :public AbstractProduct

{

public:

        // 通过构造函数,向基类传递参数

        Apple(const string name, const double price) : AbstractProduct(name, price)

        {

        }

 

        // 实现基类中的纯虚函数

        string get_name() const

        {

                  return name;

        }

 

        // 实现基类中的纯虚函数

        double get_price() const

        {

                  return price;

        }

 

        ~Apple()

        {

                  cout << "This is in destructor of Apple..." << endl;

        }

};

 

class Car :public AbstractProduct

{

public:

        // 通过构造函数,想基类传递参数

        Car(const string name, const double price) : AbstractProduct(name, price)

        {

        }

 

        // 实现基类中的纯虚函数

        string get_name() const

        {

                  return name;

        }

 

        // 实现基类中的纯虚函数

        double get_price() const

        {

                  return price;

        }

 

        ~Car()

        {

                  cout << "This is in destructor of Car..." << endl;

        }

};

 

class AbstractFactory

{

public:

        //virtual AbstractProduct* create() = 0;

        //上面一句可以由下面的语句代替,由于使用了RAII技术,因此可以不用担心内存泄漏问题

        virtual auto_ptr<AbstractProduct> create() = 0;

 

        virtual ~AbstractFactory()

        {

                  cout << "This is in destructor of AbstractFactory..." << endl;

        }

};

 

class AppleFactory :public AbstractFactory

{

        //AbstractProduct* create()                          // 修改函数返回类型为auto_ptr<AbstractProduct>

        auto_ptr<AbstractProduct> create()

        {

                  //return new Apple("苹果", 10.1);

                  //上面一句可以由下面两个语句代替,由于使用了RAII技术,因此可以不用担心内存泄漏问题

                  auto_ptr<AbstractProduct> ap(new Apple("苹果", 10.1));

                  return ap;

        }

 

        ~AppleFactory()

        {

                  cout << "This is in destructor of AppleFactory..." << endl;

        }

};

 

class CarFactory :public AbstractFactory

{

        //AbstractProduct* create()                          // 修改函数返回类型为auto_ptr<AbstractProduct>

        auto_ptr<AbstractProduct> create()

        {

                  //return new Car("汽车", 200000.2);

                  //上面一句可以由下面两个语句代替,由于使用了RAII技术,因此可以不用担心内存泄漏问题

                  auto_ptr<AbstractProduct> ap(new Car("汽车", 200000));

                  return ap;

        }

 

        ~CarFactory()

        {

                  cout << "This is in destructor of CarFactory..." << endl;

        }

};

 

// FactoryMethod.cpp

#include"FactoryMethod.h"

 

//测试代码

int main(void)

{

        //AbstractFactory *af;

        //AbstractProduct *ap;

 

        //af = new AppleFactory;

        auto_ptr<AbstractFactory> af(new AppleFactory);

        //ap = af->create();

        auto_ptr<AbstractProduct> ap(af->create());

 

        cout << ap->get_name() << ", " << ap->get_price() << endl;

 

        //delete af;

        //delete ap;

        //af = 0;

        //ap = 0;

 

        //af = new CarFactory;

        auto_ptr<AbstractFactory> tempAF(new CarFactory);

        af = tempAF;

        //ap = af->create();

        auto_ptr<AbstractProduct> tempAP(af->create());

        ap = tempAP;

        cout << ap->get_name() << ", " << ap->get_price() << endl;

 

        //delete af;

        //delete ap;

        //af = 0;

        //ap = 0;

 

        return 0;

}

上面代码的执行结果为:

苹果, 10.1

This is in destructor of AppleFactory...

This is in destructor of AbstractFactory...

This is in destructor of Apple...

This is in destructor of AbstractProduct...

汽车, 200000

This is in destructor of Car...

This is in destructor of AbstractProduct...

This is in destructor of CarFactory...

This is in destructor of AbstractFactory...

结果符合预期,相关动态创建的对象,也自动得到了销毁。如果不使用auto_ptr(即对应的被注释的部分),那么在main函数中必须由程序员自己手动去销毁相关动态创建的对象,如main函数中被注释的那些代码那样。

 

具体的产品实例,在具体的产品工厂内创建的。

 

对于客户端代码(如上述main函数)如果因为增加新的具体产品,只有一个地方即

auto_ptr<AbstractFactory> af(new AppleFactory);

语句中带下划线部分需要修改代码外,其他只需进行相关的代码扩展,即增加一个具体的产品类和对应的具体产品工厂类即可。因此这样将代码改动减少到了最少。这符合OCP

 

很明显,Factory Method模式很好地解决了单个对象的需求变化。

 

最后说明一下:

FactoryMethod.h中各类的代码应当分布在不同的文件中,这样在有扩展的时候,就不会修改该文件,而是另外增加两个文件(一个具体产品类,一个具体产品工厂)。这样做的目的,一方是因为OCP,另外一方面是可以大幅度提高编译效率。

 
转:http://patmusing.blog.163.com/blog/static/135834960201002302636911/
 
原创粉丝点击