boost :: function có một mẫu nhà máy khá linh hoạt: http://www.boost.org/doc/libs/1_54_0/libs/feftal/factory/doc/html/index.html
Mặc dù vậy, sở thích của tôi là tạo các lớp bao bọc ẩn cơ chế tạo đối tượng và ánh xạ. Kịch bản phổ biến mà tôi gặp phải là cần ánh xạ các lớp dẫn xuất khác nhau của một số lớp cơ sở thành các khóa, trong đó tất cả các lớp dẫn xuất đều có sẵn một chữ ký hàm tạo chung. Đây là giải pháp tôi đã đưa ra cho đến nay.
#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
Tôi thường phản đối việc sử dụng macro nặng, nhưng tôi đã tạo ra một ngoại lệ ở đây. Đoạn mã trên tạo GENERIC_FACTORY_MAX_ARITY + 1 phiên bản của một lớp có tên GenericFactory_N, cho mỗi N trong khoảng từ 0 đến GENERIC_FACTORY_MAX_ARITY.
Sử dụng các mẫu lớp được tạo ra rất dễ dàng. Giả sử bạn muốn một nhà máy tạo các đối tượng dẫn xuất BaseClass bằng cách sử dụng ánh xạ chuỗi. Mỗi đối tượng dẫn xuất lấy 3 số nguyên làm tham số hàm tạo.
#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);
Hàm hủy của lớp GenericFactory_N là ảo để cho phép các mục sau.
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;
Lưu ý rằng dòng này của macro máy phát điện chung
#define BOOST_PP_FILENAME_1 "GenericFactory.hpp"
Giả sử tệp tiêu đề chung của nhà máy được đặt tên là GenericFactory.hpp