【问题标题】:Should my document class have methods for printing or should there be a dedicated printer class? [closed]我的文档类应该有打印方法还是应该有专用的打印机类? [关闭]
【发布时间】:2019-02-10 19:33:06
【问题描述】:

我想编写一个打印文档的应用程序。

哪种设计更好?变体 A:

class Document
{
    public string Title { get; set; }
    public string Author { get; set; }
    public string Content { get; set; }
    // ...
}

class DocumentPrinter
{
    public void PrintDocument(Document document)
    {
       // ...
    }
}

这将提供一个专用的 DocumentPrinter 类,它只进行打印。或者向 Document 类本身添加一个 Print() 方法会更好,就像这里(变体 B):

public class Document
{
    public string Title { get; set; }
    public string Author { get; set; }
    public string Content { get; set; }

    public void Print()
    {
       // ...
    }
}

两种变体的隐含权衡是什么?哪一个在可维护性和架构方面更好?

我会说变体 A 更好,因为它会满足“ 单一责任原则”。但变体 B 使用起来会更直观。

【问题讨论】:

  • 也许这个问题更适合softwareengineering.stackexchange.com
  • 我会使用一个单独的类来匹配单一职责。想象一下,如果以后有理由将文档导出为 PDF,然后有另一个理由将其导出为 PNG 等......你什么时候会分解它?我会更进一步,让您的文档实现一个接口,并让您的 print/pdf/png 处理器接受该接口作为他们的输入。
  • 从维护的角度来看,我认为第一种方式更好。随着打印机或文档的公共接口或实现细节发生变化,另一个不需要也发生变化。我也不同意变体 B 更直观。至少,我不希望该方法成为文档类的一部分。最后,如果您想获得哲理,文档不会自行打印。
  • @Dragonthoughts 为什么要为文档本身添加一个界面?我没有看到拥有更多变体的任何好处。它只是一个保存数据的对象。当然,DocumnetPrinter 类的情况正好相反(因为可以添加不同的输出格式)。
  • 它分离了文档和打印机实现之间的任何直接依赖关系。

标签: c# oop architecture


【解决方案1】:

我会做如下。您的 Printer 类不需要了解文档的内在特性,因为它可以获得要打印的最终输出。

interface IPrintable
{
     string GetOutput();
}

class Document : IPrintable
{
    ...
    public string GetOutput()
    {
        return ...; // final formatted representation
    }
}

class Printer
{
    public void Print(IPrintable printable)
    {
        var output = printable.GetOutput();
        ... // print it out
    }
}

【讨论】:

    【解决方案2】:

    对这个问题最常见的一般反应是给Document一个格式化函数(可能在接口中定义),它接受一个字符串并将其参数代入其中,然后有一个PrinterDocumentPrinter类应用给定的格式,然后“打印”结果(无论这意味着写入输出、将其发送到打印队列、保存 PDF 文件还是通过电子邮件将请求发送给打印公司)。

    如果这听起来像是您在不久的将来可能想做的事情,那就去做吧。否则,您将不得不以一种或另一种方式将您的 Print 逻辑与您的 Document 逻辑紧密耦合,因此请选择最简单的。

    【讨论】:

      【解决方案3】:

      在我看来,解决方案 A 更好,因为它遵循 SOLID,并且更易于维护、扩展……您的应用程序。

      另外,我认为你应该基于一个接口(可能是IDocumentPrinter)来实现DocumentPrinter。

      interface IDocumentPrinter
      {
          void PrintDocument(Document document);
      }
      
      class DocumentPrinter: IDocumentPrinter
      {
          public void PrintDocument(Document document)
          {
             // ...
          }
      }
      

      让我们想一想:如果将来您需要拥有许多打印机,那么使用解决方案 A(包括 IDocumentPrinter)您只需要实现基于 IDocumentPrinter 的新类(DocumentPrinterA、DocumentPrinterB、...)而您不需要更改您当前的类(Document、DocumentPrinter)并且不会违反 Open-Close 原则。

      【讨论】:

        猜你喜欢
        • 2013-12-22
        • 2011-06-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-03
        • 1970-01-01
        • 2022-12-02
        • 1970-01-01
        相关资源
        最近更新 更多