工厂方法(虚构造器)

Posted kuikuitage

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了工厂方法(虚构造器)相关的知识,希望对你有一定的参考价值。

工厂方式的核心是定义一个抽象工厂接口类,将对象的创建工作推迟到工厂接口类的子类中

即不同对象创建依赖继承自工厂基类的关联工厂子类。

相较于简单工厂,工厂方法模式符合开闭原则,同时实现了解耦,但出现了类膨胀即所有产品的实例对象都需要有各自的工厂
如果是要克服简单工厂模式的局部耦合缺陷,也可以考虑使用C++模板形式实现简单工厂。
base.h

#ifndef BASE_H
#define BASE_H

#include <string>
using namespace std;

class IBase
{
public:
    virtual ~IBase();
    virtual const string& getName() const;
    virtual void setName(const string& name);
protected:
    IBase();
    IBase(const string& name);
private:
    string m_name;
};

#endif // BASE_H

base.cpp

#include <iostream>
#include "base.h"

const string& IBase::getName() const
{
    return m_name;
}

void IBase::setName(const string& name)
{
    m_name = name;
}

IBase::IBase()
{
    cout << "constructor IBase" << endl;
}

IBase::IBase(const string& name)
{
    m_name = name;
}

IBase::~IBase()
{
    cout << "destructor IBase" << endl;
}

imp.h

#ifndef IMP_H
#define IMP_H

#include "base.h"

class CImpSamA : public IBase
{
public:
    CImpSamA();
    CImpSamA(string name);
    ~CImpSamA();
};

class CImpSamB : public IBase
{
public:
    CImpSamB();
    CImpSamB(string name);
    ~CImpSamB();
};
#endif // IMP_H

imp.cpp

#include <iostream>
#include "imp.h"

CImpSamA::CImpSamA():IBase("CImpSamA")
{
    cout << "constructor CImpSamA NoParam " << endl;
}

CImpSamA::CImpSamA(string name):IBase(name)
{
    cout << "constructor CImpSamA " << endl;
}

CImpSamA::~CImpSamA()
{
    cout << "destructor CImpSamA " << endl;
}

CImpSamB::CImpSamB():IBase("CImpSamB")
{
    cout << "constructor CImpSamB NoParam " << endl;
}

CImpSamB::CImpSamB(string name):IBase(name)
{
    cout << "constructor CImpSamB " << endl;
}

CImpSamB::~CImpSamB()
{
    cout << "destructor CImpSamB " << endl;
}

factory.h

#ifndef FACTORY
#define FACTORY

#include "base.h"

class CFactoryA
{
public:
    //返回CImpSamA*类型
    template<class T>
    static T* Create()
    {
         return new T();
    }
};

class CFactoryB
{
public:
    //返回IBase*类型
    template<class T>
    static IBase* Create()
    {
        return new T();
    }
};

#endif // FACTORY

main.cpp

#include <QCoreApplication>
#include <iostream>
#include "factory.h"
#include "imp.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    //返回CImpSamA*类型
    IBase* pImp = CFactoryA::Create<CImpSamA>();
    if(NULL != pImp)
    {
        pImp->setName("New IMPA");
        cout << pImp->getName() << endl;
        delete pImp;
        pImp = NULL;
    }
    //返回IBase*类型
    pImp = CFactoryB::Create<CImpSamB>();
    if(NULL != pImp)
    {
        cout << pImp->getName() << endl;
        delete pImp;
        pImp = NULL;
    }

    return a.exec();
}

优点:

  • 相较于简单工厂,将原本耦合在一个接口的创建方法,通过模板实例化多个具体创建实现,解除了局部耦合。
  • 相较于工厂方法,避免了不同工厂基类造成的类膨胀。

缺点:

  • 使用模板经过二次编译存在开销(编译期)
  • 需要工厂的具体产品类型对外可见才能在外部进行创建工作,违反了封装特性,必须在调用模板的地方或者模板实现中引入(有声明)相关产品对象。
  • 依然不符合开闭原则,一旦需要引入新的产品类型,需要增加新的模板实例化调用代码。

抛开优缺点,简单工厂是将产品创建工作集中到一个函数来创建,模板方法实现实际上是通过模板扩展出多个函数达到创建不同产品的目的。

下面来看真正的 工厂方法。
factory.h

#pragma once

#include "imp.h"

class ISplitterFactory
{
public:
        virtual ISplitter* CreateSplitter() = 0;
        virtual ~ISplitterFactory(){}
};

class CBinarySplitterFactory : public ISplitterFactory
{
public:
        ISplitter* CreateSplitter();
};

class CTxtSplitterFactory : public ISplitterFactory
{
public:
        ISplitter* CreateSplitter();
};

class CPictureISplitterFactory : public ISplitterFactory
{
public:
        ISplitter* CreateSplitter();
};

factory.cpp

#include "factory.h"
#include "imp.h"

ISplitter* CBinarySplitterFactory::CreateSplitter()
{
    return new BinarySplitter();
}

ISplitter* CTxtSplitterFactory::CreateSplitter()
{
    return new TxtSplitter();
}

ISplitter* CPictureISplitterFactory::CreateSplitter()
{
    return new PictureISplitter();
}

imp.h

#pragma once

class ISplitter
{
public:
        virtual void split() = 0;
        virtual ~ISplitter(){}
};

class BinarySplitter : public ISplitter
{
public:
    void split();
};

class TxtSplitter : public ISplitter
{
public:
    void split();
};

class PictureISplitter : public ISplitter
{
public:
    void split();
};

imp.cpp

#include <iostream>
#include "imp.h"

using namespace std;

void BinarySplitter::split()
{
    cout << "split BinarySplitter" << endl;
}

void TxtSplitter::split()
{
    cout << "split TxtSplitter" << endl;
}

void PictureISplitter::split()
{
    cout << "split PictureISplitter" << endl;
}

main.cpp

#include <cstdio>
#include <cstdlib>
#include "factory.h"
#include "imp.h"

class Fun
{
    ISplitterFactory* m_pFactory;
public:
    Fun(ISplitterFactory* factory)
    {
        m_pFactory = factory;
    }
    ~Fun(){}
    void test()
    {
        ISplitter *splitter = m_pFactory->CreateSplitter();
        splitter->split();
                delete splitter ;
                splitter = NULL;
    }
};

int main()
{
    //对象创建
    ISplitterFactory* factory = new CPictureISplitterFactory();
    
    //在form的内部factory只需要知道接口,不需要知道具体类型。在form内部并不知道factory的类型
    Fun form(factory);
    form.test();
    //这里也只是依赖了facotory ,不关心factory的真实类型
    ISplitter *splitter = factory->CreateSplitter();
    splitter->split();
    delete splitter ;
    splitter = NULL;
    delete factory;
    factory = NULL;

    return 0;
}

优点:

  • 隔离了类对象的使用者和具体类型之间的耦合关系

缺点:

  • 不同对象的创建方法参数要相同,即不同工厂的CreateSplitter签名需要一致。

以上是关于工厂方法(虚构造器)的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之工厂方法模式

iOS:个人浅谈工厂模式

片段通信问题(尝试调用虚方法)

设计模式——简单工厂工厂方法与抽象工厂

代码优化考虑使用静态工厂方法取代构造器

面向对象:继承抽象类抽象方法虚方法