我将一堆不同的对象保存并重新加载到一个文件中,这些对象都是从一个公共基础派生的,显然我需要存储类名(或类似的名称),以便在重新加载时创建正确的对象类型。
保存很容易:
class Base
{
virtual string className() const = 0;
void saveToFile()
{
write(className());
... other writing stuff
}
}
class Derived1: public Base
{
string className() const { return "Derived1"; };
...
}
class Derived2: public Base
{
string className() const { return "Derived2"; };
...
}而且,如果你不介意复制字符串,加载也很容易……
static Base * Base::factory(const String &cname)
{
if (cname == "Derived1")
return new Derived1;
else if (cname == "Derived2")
return = new Derived2;
else ...
}
void load()
{
String cname = readString();
Base * obj(Base::factory(cname);
obj->readIt();
}但是,重复的字符串冒犯了我对DRY的看法:理想情况下,className()可以是static virtual,但这是不允许的。我有一种感觉,我错过了一种明显的“干净”的方式,但我还看不到。有什么建议吗?
注意:好的,代码使用了一个工厂方法进行了轻微的调整。请注意,这实际上并没有解决问题!
注意#2:上面的代码并没有试图完美地表示最终的工厂模式。我不关心基类和派生类之间不必要的链接,也不关心扩展层次结构的潜在困难。我正在寻找能够简化代码而不是使其复杂化的答案。
发布于 2012-09-17 20:26:16
这就是你所能做的最好的事情了,你可以通过将if包装在工厂类中来清理它。
发布于 2012-09-17 21:27:45
这里有两件事。首先,为了避免必须写出两次名称,我在过去使用了类似以下内容:
class Derived : public Base
{
// ...
static char const* className() { return "Derived"; }
virtual char const* getClassName() const { return className(); }
// overrides virtual function in the base class...
};此外,如果您希望能够从外部源读取类,则需要某种类型的静态工厂函数,该函数向此类函数的映射注册自身。我会继续在Base中执行此操作
class Base
{
// ...
protected:
class Factory
{
protected:
Factory( std::string const& type );
public:
virtual Base* constructFromFile( std::istream const& source ) const = 0;
};
typedef std::map <std::string, Factory const*> FactoryMap;
static FactoryMap& factories();
template <typename Derived>
class ConcreteFactory : public Factory
{
public:
ConcreteFactory() : Factory( Derived::className() ) {}
virtual Base* constructFromFile( std::istream const& source ) const
{
return new Derived( source );
}
};
public:
static Base* readFromFile( std::istream& source );
};
Base::FactoryMap&
Base::factories()
{
static FactoryMap theOneAndOnly;
return theOneAndOnly;
}
Base::Factory::Factory( std::string const& type )
{
std::pair <FactoryMap::iterator, bool> results
= factories().insert( std::make_pair( type, this ) );
assert (results.second);
}
Base* Base::readFromFile( std::istream& source )
{
std::string type = readType( source );
FactoryMap::const_iterator factory = factories().find( type );
if ( factory == factories().end() ) {
throw UnknownType(...);
}
return factory->second->constructFromFile( std::istream& source );
}最后,对于每个派生类,您必须定义一个接受std::istream&的构造函数和一个Base::ConcreteFactory <Derived>的静态实例。(如上所述,这必须是静态成员。)
发布于 2012-09-17 20:26:51
显然,您需要工厂模式。点击此处了解更多信息http://www.codeproject.com/Articles/363338/Factory-Pattern-in-Cplusplus
https://stackoverflow.com/questions/12459112
复制相似问题