我正在阅读《现代C ++设计》这本书,看到下面的代码在“ 8.1需求对象工厂”中进行了解释,我对此有些怀疑。


我的理解是,每当写入一个derivedDocument类时,都应该在新的derivedDocumentManager类中覆盖“ CreateDocument()”吗?
如果是,那么派生的documentManager太多,需要自己的Factory方法!!!
如果否,则“ CreateDocument()”应带有一个ID,以便它可以准确地确定要在一个对象中创建什么。但这也意味着,每次创建一个派生文档时,他还应该找到正确的documentManager并更新CreateDocument()方法。但是我们必须决定是否拥有一个documentManager的工厂,因为它们可能很少或很多。

我的主要疑问是,这是否是一个解决方案,还是我错过了要点。根据这本书,CreateDocument()是GoF本书的工厂方法。 “ CreateDocument()”至少基于一个ID和许多条件来创建一个新的衍生物文档。但是很多派生文档管理器没有意义。


本书中的DocumentManager

class DocumentManager
{
    ...
public:
    Document* NewDocument();
private:
    virtual Document* CreateDocument() = 0;
    std::list<Document*> listOfDocs_;
};

Document* DocumentManager::NewDocument()
{
    Document* pDoc = CreateDocument();
    listOfDocs_.push_back(pDoc);
    ...
    return pDoc;
}


客户代码:

Document* GraphicDocumentManager::CreateDocument()
{
    return new GraphicDocument;
}

最佳答案

更新:您的问题已经过大量编辑,以使其具有不同的重点。还有几点:


您似乎在想,对“工厂”的任何提及都必然涉及一个具体的功能,即接受一些输入并根据输入吐出许多可能的动态类型之一的实例。那只是工厂的一种类型,而不是代码中显示的类型。


阅读有关Factory Method Pattern的内容,希望您会意识到这就是您所拥有的。它可以让您执行以下操作:

std::string compress(DocumentManager& d, const std::string& uncompressed)
{
    std::unique_ptr<Document> doc = std::make_unique(d.NewDcoument());
    doc = uncompressed;  // interpret to form document of whatever type
    return zlib::compress(d.data(), d.size());  // compress as binary blob
}


在这里,可以使用一些原始输入来调用一个compress()函数,并尝试首先创建正确的调用者指定类型的文档,然后将一些数据填充到其中并进行压缩。

工厂方面的能力是在不知道所涉及的具体类型的情况下进行压缩以创建对象的能力,因为-未模板化且缺少任何切换-否则无法在许多构造函数之间进行选择。



根据原始问题回答...


  我们是否将对象创建问题从Document移到DocumentManager类。我的意思是我们必须创建[具体] DocumentManager吗?


关键是不是-在创建特定类型的list<Document*>时要额外保留记录(在本例中为Document)。

如果我们让客户端代码直接创建Document,那么拥有这样的列表将取决于客户端每次创建对象时都会更新列表(或者需要对Document构造函数进行侵入式更改)。如果要说出创建对象的时间添加时间戳,我们必须修改客户端代码中创建任何类型的Document的每个位置。

如果没有DocumentManager基类,则必须将相似的逻辑和数据成员放入任意数量的GraphicDocumentManagerTextDocumentManagerAudioDocumentManager等中,并且不能多态地处理这些管理器。 (例如,创建vector<DocumentManager*>,编写ala void f(DocumentManager&);函数。


  如何跟踪由许多独立客户端创建的所有DocumentManager派生类?


设计中没有打算这样做的东西,并且C ++没有内省的功能可让您枚举派生的类型-既不是在编译时,也不是在程序开始运行时。但是,如果您准备等待被调用的NewDocument,则可以记录源自DocumentManager的具体对象的地址和/或访问其RTTI信息(例如,可以让您计算具有已创建,或尝试显示动态类型的实现定义的(可能为空)name()字段。...


  listOfDocs_不应为静态,而DocumentManager不应为单例。


可能不会。该程序可能想要做一些事情,例如为每个TCP客户端,每个文件系统,每个用户等保留一个DocumentManager对象-那么为什么不自然地限制它呢?轻松创建更好的DocumentManager类型,然后让客户端代码应用单例包装器(例如,函数返回static实例)(如果这实际上对他们有用),则更好。这也使测试变得更加容易:您可以自由创建DocumentManager,运行测试,让析构函数运行,创建另一个等等。


  我的主要疑问是,根本没有解决方案,还是我缺少了一点。


似乎您缺少了一些“位图”,但是如果您没有这本书或您需要更一般的问题/理解陈述,就很难知道还有什么可能。


  根据书“ CreateDocument()”,这是GoF书的工厂方法。但是我无法理解以上几点。


是的-这是一种工厂方法,因为它创建许多不同的动态类型的对象中的任何一种,但返回指向基类的指针,通过该指针可以对它们进行多态处理。

08-26 10:47