"Modern C++ Design" DocumentManager 设计是否正确?

Is "Modern C++ Design" DocumentManager design correct?

我正在翻"Modern C++ Design"这本书,看到《8.1 对象工厂的必要性》中解释了下面的代码,我有些疑惑。

  1. 我的理解是,每次写入 derivedDocument class 时,"CreateDocument()" 都应该在新的 derivedDocumentManager class 中被覆盖吗?
  2. 如果是,那么派生的 documentManagers 就会太多,需要自己的工厂方法!!!
  3. 如果否,那么 "CreateDocument()" 应该使用一个 ID,以便它可以准确地决定在一个对象中创建什么。但这也意味着,每次创建 derivedDocument 时,他还应该找到正确的 documentManager 并更新 CreateDocument() 方法。但是我们必须决定是否拥有 documentManagers 工厂,因为它们可能很少也可能很多。

    我的主要疑问是这是否是一个解决方案,或者我是否忽略了重点。按照书上的说法,CreateDocument()是GoF书中的工厂方法。 "CreateDocument()" 基于 ID 和许多条件创建一个新的 derivedDocument 至少是有意义的。但是很多derivedDocumentManager没有意义。

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;
}
  1. 我们不是把对象创建的问题从Document转移到了DocumentManagerclass吗?我的意思是我们必须创建音乐会 DocumentManager 吗?我们如何跟踪由这么多独立客户创建的 DocumentManager 的所有派生 classes?

    • CreateDocument是工厂方法。 DocumentManager 不负责创建对象。派生管理器 (GraphicDocumentManager) 的 CreateDocument 将以其特定方式创建文档。
  2. 不应该 listOfDocs_ 是静态的并且 DocumentManager 是单例的吗?

    • 是的,我想是的。理想情况下不能有两个经理 classes。但是我不知道派生 classes.
    • 的单身人士的并发症
  3. 我的主要疑问是是否有解决方案,或者我是否遗漏了重点。 按照书上的说法,CreateDocument()是GoF书中的工厂方法。但是我无法理解以上几点。

    • 这只是工厂方法。

请阅读这篇文章link: http://www.codeproject.com/Articles/35789/Understanding-Factory-Method-and-Abstract-Factory

更新:您的问题已经过大量编辑,以提供不同的关注点。补充几点:

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

阅读有关 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() 函数,并尝试首先创建一个正确的调用者指定类型的文档,然后将一些数据填充到其中并压缩它....

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


根据原问题回答...

Are we not moving the problem of object creation from Document to DocumentManager class. I mean we have to create [concrete] DocumentManager?

这就是重点,不是吗 - 围绕特定类型的 Document 的创建进行额外的记录保存(在本例中为 list<Document*>)。

如果我们让客户端代码直接创建 Documents,拥有这样一个列表将取决于客户端在每次创建对象时更新列表(或者需要对 Document 构造函数进行侵入性更改).如果我们想说在对象创建时添加时间戳,我们必须修改客户端代码中创建任何类型 Document.

的每个地方

如果我们没有 DocumentManager 基础 class,我们将不得不将类似的逻辑和数据成员放入任意数量的 GraphicDocumentManagerTextDocumentManager , AudioDocumentManager 等,并且无法多态地处理这些管理器(例如创建 vector<DocumentManager*>,编写函数 ala void f(DocumentManager&);.

How to keep track of all the derived classes of DocumentManager, created by many independent clients?

设计中没有任何内容旨在这样做,而且 C++ 没有让您枚举派生类型的内省工具——无论是在编译时还是程序启动时都没有 运行ning。但是,如果您准备等待 NewDocument 被调用,您可以记录具体 DocumentManager 派生对象的地址 and/or 访问它们的 RTTI 信息(例如,让您计算已创建的不同类型的文档,或尝试显示动态类型的实现定义(可能为空)name() 字段....

Should not the listOfDocs_ be static and DocumentManager be a singleton.

可能不会。该程序可能想要为每个 TCP 客户端、每个文件系统、每个用户等保留一个 DocumentManager 对象——那么为什么要不自然地限制它呢?创建一个更灵活的 DocumentManager 类型,然后让客户端代码应用一个单例包装器(例如函数返回一个 static 实例),如果这对它们确实有用,这很容易也更好。这也使测试更容易:您可以自由创建 DocumentManagers,运行 测试,让析构函数 运行,创建另一个等等....

My main doubt is, is that a solution at all or I am missing some point.

您似乎遗漏了一些东西 "bit picture",但是没有手头的书或更一般的书 question/statements-of-understand,很难知道它可能还有什么。

According to the book "CreateDocument()" is the GoF book's factory method. But I am not able to understand the above points.

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