我的问题或多或少与需要的设计模式相同,以删除对象创建中的枚举和切换语句,但是我认为抽象的出厂模式在这里不适合使用。
我目前正在计划某些现有的DAL/ORM混合物库的重构/重新实现。在现有代码中的某个地方有看起来像这样的代码:
class Base
{
static Base * create(struct Databasevalues dbValues)
{
switch(dbValues.ObjectType)
{
case typeA:
return new DerivedA(dbValues);
break;
case typeB:
return new DerivedB(dbValues);
break;
}
}
}
class DerivedA : public Base
{
// ...
}
class DerivedB : public Base
{
// ...
}
因此,负责数据库通信的库将一个结构填充,其中包含有关数据库实体的所有信息,然后调用上面的创建()方法来实际创建ORM中的对应对象。但是我不喜欢一个小型班级了解其所有派生类的想法,也不喜欢Switch语句。我还想避免仅出于创建这些对象而创建另一个类。您如何看待当前的方法?您将如何实现此功能?
在这里已经讨论了数百万次。如果您不想创建单独的工厂课程,可以做到这一点。
class Base
{
public:
template <class T>
static void Register (TObjectType type)
{
_creators[type] = &creator<T>;
}
static Base* Create (TObjectType type)
{
std::map <TObjectType, Creator>::iterator C = _creators.find (type);
if (C != _creators.end())
return C->second ();
return 0;
}
private:
template <class T>
static Base* creator ()
{
return new T;
}
private:
typedef Base* (::*Creator) ();
static std::map <TObjectType, Creator> _creators;
};
int main ()
{
Base::Register <Derived1> (typeA);
Base::Register <Derived2> (typeB);
Base* a = Base::Create (typeA);
Base* b = Base::Create (typeB);
}
,假设您将开关替换为映射,例如 map<ObjectType, function<Base* (DatabaseValues&)>>
。
现在,工厂(可能不在基类中),不需要了解所有子类。
但是,必须以某种方式填充地图。这意味着要么填充它(因此您的了解所有子类问题问题刚刚从一个地方推到另一个地方),要么您需要子类使用静态初始化来在地图中注册其出厂功能。/p>
无论您做什么,都需要开关案例或其他将隐藏相似逻辑的构造。
您可以和应该做的是从基础上删除创建方法 - 您完全正确,它不应该意识到它的派生方法。此逻辑属于另一个实体,例如工厂或控制器。
只是不使用枚举。它们不是OO的构造,这就是为什么Java一开始就没有它们(不幸的是,压力太大而无法添加它们)。
考虑而不是这样的枚举:
enum Types {
typeA,
typeB
};
这种不需要开关的结构(我认为另一个非OO构造)和地图:
types.h
class Base;
class BaseFactory {
public:
virtual Base* create() = 0;
};
class Types {
public:
// possible values
static Types typeA;
static Types typeB;
// just for comparison - if you do not need - do not write...
friend bool operator == (const Types & l, const Types & r)
{ return l.unique_id == r.unique_id; }
// and make any other properties in this enum equivalent - don't add them somewhere else
Base* create() { return baseFactory->create(); }
private:
Types(BaseFactory* baseFactory, unsigned unique_id);
BaseFactory* baseFactory;
unsigned unique_id; // don't ever write public getter for this member variable!!!
};
types.cpp
#include "Types.h"
#include "Base.h"
#include "TypeA.h"
#include "TypeB.h"
namespace {
TypeAFactory typeAFactory;
TypeBFactory typeAFactory;
unsigned unique_id = 0;
}
Types Types::typeA(&typeAFactory, unique_id++);
Types Types::typeA(&typeBFactory, unique_id++);
所以您的示例(如果您真的需要此功能):
class Base
{
static Base * create(struct Databasevalues dbValues)
{
return dbValues.ObjectType.create();
}
};
缺少零件应该易于实现。