代码之家  ›  专栏  ›  技术社区  ›  adrianm

要避免的类(代码完成)

  •  38
  • adrianm  · 技术社区  · 15 年前

    我对代码完整书中的一段有些困惑。

    在“要避免的类”一节中,它显示:

    “避免用动词命名类只有行为但没有数据的类通常不是真正的类。考虑将类似databaseinitialization()或stringbuilder()的类转换为其他类上的例程。”

    我的代码主要由没有数据的动词类组成。有invoicereaders、pricecalculator、messagebuilders等,我这样做是为了将类集中到每个任务上。然后我为其他功能向其他类添加依赖项。

    如果我正确理解段落,我应该使用

    class Webservice : IInvoiceReader, IArticleReader {
        public IList<Invoice> GetInvoices();
        public IList<Article> GetArticles();
    }
    

    而不是

    class InvoiceReader : IInvoiceReader {
        public InvoiceReader(IDataProvider dataProvider);
        public IList<Invoice> GetInvoices();
    }
    
    class ArticleReader : IArticleReader {
        public ArticleReader(IDataProvider dataProvider);
        public IList<Article> GetArticles();
    }
    

    编辑 谢谢你的回复。

    我的结论是,我目前的代码比OO更SRP,但它也受到“贫血域模型”的困扰。

    我相信这些见解将来会对我有所帮助。

    10 回复  |  直到 15 年前
        1
  •  20
  •   Ash    15 年前

    诸如invoicereader、pricecalculator、messagebuilder、articlereader、invoicereader等类名实际上不是动词名。它们实际上是“名词代理名词”类名。见 agent nouns .

    动词类名可以是诸如validate、operate、manage等。显然,它们最好用作方法,而且作为类名会非常尴尬。

    “名词代理名词”类名的最大问题是,它们对类的实际操作(如UserManager、DataProcessor等)几乎没有意义。结果,他们更容易膨胀,失去内部凝聚力。(参见 Single Responsibility Principle )

    因此,具有IInvoiceReader和IArticleReader接口的WebService类可能是更清晰、更有意义的OO设计。

    这为您提供了简单、明显的名词类名“WebService”,以及“名词代理名词”接口名,它们清楚地说明了WebService类可以为调用者做什么。

    您也可以通过在另一个名词前面加前缀来赋予实际类更多的含义,例如paymentwebservice。

    但是,在更具体地描述类可以为调用方做什么时,接口总是比单个类名更好。随着类越来越复杂,新的接口也可以添加有意义的名称。

        2
  •  11
  •   Aaronaught    15 年前

    我个人忽略了这个“规则”。.NET框架本身充满了“动词”类: TextReader , BinaryWriter , XmlSerializer , CodeGenerator , StringEnumerator , HttpListener , TraceListener , ConfigurationManager , TypeConverter , RoleProvider …如果您认为框架设计得不好,那么无论如何,不要使用这样的名称。

    史蒂夫的意图是可以理解的。如果您发现自己在几十个类上创建几十个类只是为了执行特定的任务,那么这很可能是 anemic domain model ,其中的对象 应该 能够自己做这些事情的不是。但在某些时候,你必须在“纯”OOP和 SRP .

    我的建议是:如果你发现自己创建了一个作用于单个“名词”类的“动词”类,诚实地考虑“名词”类是否可以自己执行这个动作。但不要开始创造 God Objects 或者仅仅为了避免动词类的出现而想出无意义/误导性的名字。

        3
  •  5
  •   Daniel Daranas    15 年前

    不要盲目听从任何建议。 这些只是指导方针。

    这就是说, 名词是很好的类名 ,只要它们为逻辑对象建模。因为“person”类是所有“person”对象的蓝图,所以称它为“person”非常方便,因为它允许您这样解释:“我将根据用户的输入创建一个人,但首先需要验证它…”

        4
  •  3
  •   Coincoin    15 年前

    请注意“避免”一词的用法。如果你曾经使用过它们,它不会被消灭,或者被消灭,或者被烧死。

    作者的意思是,如果你发现自己有一堆以动词命名的类,而你所做的只是静态地创建thoses类,调用一个函数并忽略它们,那么这可能是一个信号,表明你将太多的类关注分开了一点。

    但是,在某些情况下,创建类来实现一个操作是一件好事,例如当您对同一个操作有不同的策略时。一个很好的例子是iComparer<>。它所做的只是比较两件事,但有几种比较方法。

    正如作者所建议的,在这些情况下,一个很好的方法就是创建一个接口并实现它。iComparer再次出现在脑海中。

    另一种常见情况是,当操作处于重状态时,例如加载文件。将状态封装到类中可能是合理的。

        5
  •  2
  •   Mongus Pong    15 年前

    本质上,本书所说的OO设计是提取对象(名词)并识别这些对象上和对象之间发生的操作(动词)。

    名词成为对象,动词成为操作这些对象的方法。

    想法是

    接近程序模型 世界问题,程序越好 将。

    实际上,对象的有用之处在于它可以表示特定的状态。然后,您可以拥有这个类的几个不同实例,每个实例都持有不同的状态,以表示问题的某些方面。

    对于invoiceReader类

    • 您将只创建一个实例
    • 它表示的唯一状态是包含数据提供程序
    • 它只包含一个方法

    把它放在一个物体里没有好处。

        6
  •  1
  •   vgru    15 年前

    声明 只有行为但没有数据的类通常不是真正的类。 显然是错的。

    在重构中,将行为提取到单独的类中是一件很好而且很常见的事情。它可以有状态,但也不需要有状态。您需要有干净的接口,并且无论如何都要实现它们。

    此外,无状态类对于只需要很短时间的计算非常有用。您实例化它们(或者,请求某种类型的工厂来获取它们),进行必要的计算,然后将它们扔到垃圾箱中。您可以随时随地提供适当的行为“版本”。

    通常我发现一个接口的不同实现有一些状态(例如,在构造函数中设置),但有时类的类型可以完全决定它的行为。

    例如:

    public interface IExporter
    {
        /// <summary>
        /// Transforms the specified export data into a text stream.
        /// </summary>
        /// <param name="exportData">The export data.</param>
        /// <param name="outputFile">The output file.</param>
        void Transform(IExportData exportData, string outputFile);
    }
    

    可实施为

    class TabDelimitedExporter : IExporter { ... }
    class CsvExporter : IExporter { ... }
    class ExcelExporter : IExporter { ... }
    

    从中执行导出 IExportData (不管是什么)对于csv文件,您可能根本不需要任何状态。 ExcelExporter 另一方面,可以具有用于导出选项的各种属性,但也可以是无状态的。

    [编辑]

    移动 GetInvoices GetArticles 进入 WebService 类意味着您将把它们的实现与WebService类型绑定在一起。将它们放在单独的类中可以让您对发票和物品有不同的实现。总的来说,最好把它们分开。

        7
  •  0
  •   Ewan Todd    15 年前

    少关注名字。关于名字的规则只是一个不好的实践的经验法则。重要的是:

    只有行为但没有数据的类通常不是真正的类

    在您的例子中,看起来类既有数据又有行为,它们也可以称为“发票”和“文章”。

        8
  •  0
  •   iandisme    15 年前

    这要看情况而定。许多类都以读写动词命名,因为这些类还创建、维护和表示与它们读写的数据源的连接。如果你的班级正在这样做,最好是把他们分开。

    如果读卡器对象只包含解析逻辑,那么将类转换为实用方法是可行的。不过,我会使用比WebService更具描述性的名称。

        9
  •  0
  •   Ariel    15 年前

    我认为这本书建议采用如下设计:

    class Article : IIArticleReader
    {
        // Article data...
    
        public IList<Article> GetArticles(); 
    }
    
        10
  •  0
  •   Daniel Roseman    15 年前

    以下是OO中“动词与名词”的经典用法:

    http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html

    推荐文章