boost :: functional에는 매우 유연한 팩토리 템플릿이 있습니다. http://www.boost.org/doc/libs/1_54_0/libs/functional/factory/doc/html/index.html
그러나 선호하는 것은 매핑 및 객체 생성 메커니즘을 숨기는 래퍼 클래스를 생성하는 것입니다. 내가 겪는 일반적인 시나리오는 기본 클래스의 여러 파생 클래스를 키에 매핑해야하며, 파생 클래스에는 모두 공통 생성자 서명이 있습니다. 지금까지 내가 생각해 낸 해결책은 다음과 같습니다.
#ifndef GENERIC_FACTORY_HPP_INCLUDED
//BOOST_PP_IS_ITERATING is defined when we are iterating over this header file.
#ifndef BOOST_PP_IS_ITERATING
//Included headers.
#include <unordered_map>
#include <functional>
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/preprocessor/repetition.hpp>
//The GENERIC_FACTORY_MAX_ARITY directive controls the number of factory classes which will be generated.
#ifndef GENERIC_FACTORY_MAX_ARITY
#define GENERIC_FACTORY_MAX_ARITY 10
#endif
//This macro magic generates GENERIC_FACTORY_MAX_ARITY + 1 versions of the GenericFactory class.
//Each class generated will have a suffix of the number of parameters taken by the derived type constructors.
#define BOOST_PP_FILENAME_1 "GenericFactory.hpp"
#define BOOST_PP_ITERATION_LIMITS (0,GENERIC_FACTORY_MAX_ARITY)
#include BOOST_PP_ITERATE()
#define GENERIC_FACTORY_HPP_INCLUDED
#else
#define N BOOST_PP_ITERATION() //This is the Nth iteration of the header file.
#define GENERIC_FACTORY_APPEND_PLACEHOLDER(z, current, last) BOOST_PP_COMMA() BOOST_PP_CAT(std::placeholders::_, BOOST_PP_ADD(current, 1))
//This is the class which we are generating multiple times
template <class KeyType, class BasePointerType BOOST_PP_ENUM_TRAILING_PARAMS(N, typename T)>
class BOOST_PP_CAT(GenericFactory_, N)
{
public:
typedef BasePointerType result_type;
public:
virtual ~BOOST_PP_CAT(GenericFactory_, N)() {}
//Registers a derived type against a particular key.
template <class DerivedType>
void Register(const KeyType& key)
{
m_creatorMap[key] = std::bind(&BOOST_PP_CAT(GenericFactory_, N)::CreateImpl<DerivedType>, this BOOST_PP_REPEAT(N, GENERIC_FACTORY_APPEND_PLACEHOLDER, N));
}
//Deregisters an existing registration.
bool Deregister(const KeyType& key)
{
return (m_creatorMap.erase(key) == 1);
}
//Returns true if the key is registered in this factory, false otherwise.
bool IsCreatable(const KeyType& key) const
{
return (m_creatorMap.count(key) != 0);
}
//Creates the derived type associated with key. Throws std::out_of_range if key not found.
BasePointerType Create(const KeyType& key BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N,const T,& a)) const
{
return m_creatorMap.at(key)(BOOST_PP_ENUM_PARAMS(N,a));
}
private:
//This method performs the creation of the derived type object on the heap.
template <class DerivedType>
BasePointerType CreateImpl(BOOST_PP_ENUM_BINARY_PARAMS(N,const T,& a))
{
BasePointerType pNewObject(new DerivedType(BOOST_PP_ENUM_PARAMS(N,a)));
return pNewObject;
}
private:
typedef std::function<BasePointerType (BOOST_PP_ENUM_BINARY_PARAMS(N,const T,& BOOST_PP_INTERCEPT))> CreatorFuncType;
typedef std::unordered_map<KeyType, CreatorFuncType> CreatorMapType;
CreatorMapType m_creatorMap;
};
#undef N
#undef GENERIC_FACTORY_APPEND_PLACEHOLDER
#endif // defined(BOOST_PP_IS_ITERATING)
#endif // include guard
나는 일반적으로 거시적 인 매크로 사용에 반대하지만 여기서 예외를 만들었습니다. 위 코드는 0에서 GENERIC_FACTORY_MAX_ARITY (포함) 사이의 각 N에 대해 GenericFactory_N이라는 클래스의 GENERIC_FACTORY_MAX_ARITY + 1 버전의 클래스를 생성합니다.
생성 된 클래스 템플릿을 사용하는 것은 쉽습니다. 팩토리가 문자열 맵핑을 사용하여 BaseClass 파생 오브젝트를 작성하려고한다고 가정하십시오. 파생 된 각 객체는 생성자 매개 변수로 3 개의 정수를 사용합니다.
#include "GenericFactory.hpp"
typedef GenericFactory_3<std::string, std::shared_ptr<BaseClass>, int, int int> factory_type;
factory_type factory;
factory.Register<DerivedClass1>("DerivedType1");
factory.Register<DerivedClass2>("DerivedType2");
factory.Register<DerivedClass3>("DerivedType3");
factory_type::result_type someNewObject1 = factory.Create("DerivedType2", 1, 2, 3);
factory_type::result_type someNewObject2 = factory.Create("DerivedType1", 4, 5, 6);
GenericFactory_N 클래스 소멸자는 다음을 허용하기 위해 가상입니다.
class SomeBaseFactory : public GenericFactory_2<int, BaseType*, std::string, bool>
{
public:
SomeBaseFactory() : GenericFactory_2()
{
Register<SomeDerived1>(1);
Register<SomeDerived2>(2);
}
};
SomeBaseFactory factory;
SomeBaseFactory::result_type someObject = factory.Create(1, "Hi", true);
delete someObject;
일반 팩토리 생성기 매크로의이 줄은
#define BOOST_PP_FILENAME_1 "GenericFactory.hpp"
일반 팩토리 헤더 파일의 이름이 GenericFactory.hpp라고 가정합니다.