Pimpl成语指向可配置的实现

Chr*_*ews 6 c++ qt pimpl-idiom interface factory-pattern

我已经读过Pimpl有利于二进制兼容性,接口有利于轻松切换实现.我需要结合这两种技术,以便我的应用程序能够通过配置文件切换底层实现.

以下是我当前设计的布局:

Foo类:提供面向客户的API,我很担心ABI兼容性这里
一流的IFoo:接口类(所有的纯虚方法,虚析构函数)
类Vendor1Foo:实现IFoo的,使用的供应商1的库
类Vendor2Foo:实现IFoo的,使用供应商2的图书馆

通过不使用pimpl并严格使用接口,客户端代码可能如下所示:

IFoo* foo = new Vendor1Foo();
Run Code Online (Sandbox Code Playgroud)

问题是我的客户端代码根本无法了解Vendor1或Vendor2,而Foo只是我必须执行此操作的众多类之一.

我正在尝试做的所有概念如下:

class foo
{
  private:
  QScopedPointer<IFoo> pimpl;
  void initImpl();  // Reads from QSettings and initializes pimpl
}
Run Code Online (Sandbox Code Playgroud)

有什么想法可以优雅地解决这个问题吗?

我希望能够提出一些宏或模板类/方法来帮助标准化我如何处理这个并最大限度地减少违反DRY.

模板类可以作为一个辅助性PIMPL像香草萨特的大上广义PIMPL方法对C++ 11:herbsutter.com/gotw/_101,它也必须包含逻辑实例根据配置的正确实施

这里有pimpl成语,桥梁模式和工厂模式的元素.在上面的例子中,initImpl()可以被认为是一个工厂方法.我正在寻找可能会或可能不会使用所有这些模式的解决方案.

我已经看过c ++ pimpl习语:实现取决于模板参数以及SO上的大多数pimpl习语问题.标题似乎很有希望,但它对我的特定用例没有帮助.

我不能使用C++ 11并使用Qt. D-Pointers无法解决我的问题,因为它们绑定到单个实现.

Chr*_*ews 0

这个解决方案实际上对我来说很有效,所以我将其放在这里作为答案:

PimpleHelper.h是一个 Pimpl 帮助程序类,用于减少样板代码。使用 VendorFactory 实例化正确的供应商实现。多个供应商将注册他们实现给定接口的事实;对于给定的接口,只有一个供应商的实现被实例化。

    #include <QSettings>
    #include "VendorFactory.h"
    #include <cxxabi.h>

    // Pimpl Helper
    template<typename T>
    class PimplHelper
    {
        public:
        PimplHelper()
        {
            m_interfaceNameImplemented = demangle(typeid(T).name());
            initializeImpl();
        }

        T* getImpl()
        {
            return theImpl.data();
        }

        private:
        QScopedPointer< T > theImpl;
        QString m_interfaceNameImplemented;

        void initializeImpl()
        {

            // Read in configuration
            QSettings settings("AppSettings.ini", QSettings::IniFormat);
            QString vendorToUse = settings.value("VENDOR_IMPLEMENTATION_KEY", "Vendor1").toString();

            qDebug() << "Vendor to use is: " << vendorToUse << " Interface Implemented: " << m_interfaceNameImplemented;


            // Obtain an instance of the vendor's class that implements the T interface
            theImpl.reset(
                            VendorFactory<T>::create(vendorToUse, m_interfaceNameImplemented)
                         );

            if(!theImpl)
                qDebug() << "PimplHelper::initializeImpl, error resolving implementation for: "
                         << vendorToUse << " Interface Implemented: " << m_interfaceNameImplemented;
        }

        const QString demangle(const char* name)
        {
            int status = -4;
            char* res = abi::__cxa_demangle(name, NULL, NULL, &status);
            const char* const demangled_name = (status==0)?res:name;
            QString ret_val(demangled_name);
            free(res);
            return ret_val;
        }
    };
Run Code Online (Sandbox Code Playgroud)

VendorFactory.h创建由不同供应商实现的类的实例。供应商通过宏向工厂注册他们的实现。

    #include <QtCore>

    template< class T>
    class VendorFactory
    {
        private:
        typedef T* (*CreateFunc)();
        typedef QMap<QString, CreateFunc> FunctionMap;

        public:
        static T * create(const QString& vendorName, const QString& interfaceName)
        {
            typename FunctionMap::iterator it = creators()->find(vendorName + interfaceName);
            if (it == creators()->end())
                return NULL;
            return (it.value())();
        }

        static bool reg(const QString& vendorName, const QString& interfaceName, CreateFunc fun)
        {
            qDebug() << "Registering: " << vendorName + interfaceName << endl;
            creators()->insert(vendorName + interfaceName, fun);
            return true;
        }

        static FunctionMap * creators()
        {
            static FunctionMap* creators = new FunctionMap;
            return creators;
        }

        virtual ~VendorFactory() {}

    };


    /// @brief This registers a Vendor's class in the factory and adds a factory function named create_vendorImplClass()
    /// and calls VendorFactory::reg() by the help of a dummy static variable to register the function.
    /// @param vendorName A string representing the vendor's name
    /// @param vendorImplClass The class implementing the interface given by the last parameter
    /// @param interface The  interface implemented by the vendorImplClass
    #define REGISTER_IN_FACTORY( vendorName, vendorImplClass, interface ) \
        namespace { \
        interface* create_ ## vendorImplClass() {  return new vendorImplClass; } \
        static bool vendorImplClass ## _creator_registered = VendorFactory< interface >::reg( vendorName, # interface, create_ ## vendorImplClass); }
Run Code Online (Sandbox Code Playgroud)

以下是它们的使用方法:

Person.h (面向公众的 API)

#include "IPerson.h"
#include "PimplHelper.h"

// Public facing API
class Person: public IPerson
{
    public:

    Person()
    {
        impl.reset( new PimplHelper<IPerson>());
    }

    QString GetFirstName();   
    QString GetLastName();

    private:
    QScopedPointer< PimplHelper<IPerson> > impl;
};
Run Code Online (Sandbox Code Playgroud)

Person.cpp (面向公众的 API)

#include "Person.h"


QString Person::GetFirstName()
{   // I'd like to remove the call to getImpl() here
    // and just use the overloaded -> operator, but it
    // gives me a "has no member named GetFirstName()" error
    return impl->getImpl()->GetFirstName();
}

QString Person::GetLastName()
{
    return impl->getImpl()->GetLastName();
}
Run Code Online (Sandbox Code Playgroud)

PersonImpl1.h包含 Vendor1 的实现

#include "IPerson.h"
#include "VendorFactory.h"


// Private Implementation
class PersonImpl1: public IPerson
{

    public:

    PersonImpl1():
        FirstName("Jon"), LastName("Skeet")
    {}

    QString GetFirstName()
    {
        return FirstName;
    }

    QString GetLastName()
    {
        return LastName;
    }

    private:
    QString FirstName;
    QString LastName;

};

REGISTER_IN_FACTORY("Vendor1", PersonImpl1, IPerson)
Run Code Online (Sandbox Code Playgroud)

PersonImpl2.h包含 Vendor2 的实现

#include "IPerson.h"
#include "VendorFactory.h"

// Private Implementation
class PersonImpl2: public IPerson
{

    public:

    PersonImpl2(): FirstName("Chuck"), LastName("Norris")
    {}

    QString GetFirstName()
    {
        return FirstName;
    }

    QString GetLastName()
    {
        return LastName;
    }

    private:
    QString FirstName;
    QString LastName;
};

REGISTER_IN_FACTORY("Vendor2", PersonImpl2, IPerson)
Run Code Online (Sandbox Code Playgroud)

最后是main.cpp文件:

#include <QCoreApplication>
#include <QDebug>

#include "Person.h"

// The following needs to be included for the static/auto registration
// with the VendorFactory to occur. I'm not exactly sure why.
#include "PersonImpl1.h"
#include "PersonImpl2.h"

int main(int argc, char *argv[])
{
    Q_UNUSED(argc)
    Q_UNUSED(argv)

    Person* p = new Person();

    qDebug() << "The person implemented is: "
             << p->GetFirstName() << " " << p->GetLastName();

    qDebug() << "exiting";
}
Run Code Online (Sandbox Code Playgroud)

以下是迄今为止对我有帮助的其他问题的列表:

从名称实例化类?
使用 C++ 模板在编译时在 AbstractFactory 中动态注册构造函数方法
在对象工厂中注册对象创建者
C++ 中的实体/组件系统,如何发现类型并构造组件?
有没有办法从包含类名的字符串实例化对象?
静态变量未初始化
取消 std::type_info::name 的结果


归档时间:

查看次数:

1828 次

最近记录:

12 年,2 月 前