【问题标题】:Categories or Partial Classes: Pattern to Resolve "God Object" Code Smell?类别或部分类:解决“上帝对象”代码异味的模式?
【发布时间】:2011-12-22 13:32:22
【问题描述】:

类太大,难以处理。在Objective-C中,我很想使用类别来分解班级,但是:类别不只是将一个装满了太多垃圾的房子分成几个房间吗?我想同样的问题也适用于 C# 中的部分类。

在什么情况下可以使用类别来解决“类太大”的代码异味?什么时候不正确,班级真的需要"be restructured or broken into smaller classes?"

【问题讨论】:

    标签: c# objective-c design-patterns god-object


    【解决方案1】:

    将类拆分为部分并没有错。很少有开发人员会利用它。

    就个人而言,我喜欢将较大的类拆分为部分,其中每个部分的业务方面都具有相似的功能 - 但前提是在设计时看起来所说的类会变得相当大。否则,我将相关功能拆分为区域。

    例如,如果我要在数据层中拥有一个“UserService”,我可能会将其拆分为几个部分,如下所示:

    UserServiceQueries.cs
    UserServiceUpdates.cs
    UserServiceInserts.cs
    UserServiceLogicalFunctions.cs
    

    ..但是,它们包含“UserService”的部分类。我通常不经常使用 ORM,所以这对我来说是完美的,因为每个相关功能都可以变得非常大(显然这是一个基本示例)。

    最后:利用所提供的内容。如果你的班级很大,代码味道很重..你只有两个选择..重新编写它,或者拆分它(如果它肯定需要这么大的话)。

    我的意见。

    【讨论】:

    • 如果你认为 partials 类除了你的源代码之外什么都“分裂”了,那你就是在自欺欺人。你还有一个神级……它只是分成了更多的文件。如果您正在创建与代码生成无关的部分,您可能做错了什么。
    • 除了拆分代码之外,我什么也没说。事实是,有时课程确实会变得这么大。我只是解释了一种方法,我个人将相关代码从大型“上帝”类中分离出来,以便更容易理解。
    • 我只是对这种做法发表了自己的看法。它最终没有让事情变得更容易......你仍然有一个巨大的类,但现在你甚至无法在一个地方找到它的所有代码。以各种可能的方式出现更糟糕的情况。 在我看来...
    • 我完全不同意,@Andrew。我们通常将我们的类分成主代码,然后是我们所有命令定义和这些定义的处理程序的一部分,包括在 InitializeCommands 函数中设置这些命令。通过这种方式,我们知道是否且仅当它与命令相关时它位于后一个文件中,而类“主体”本身位于主文件中。此外,这还允许两个人在同一个类上工作,而无需互相踩踏:一个人可以连接 UI 代码,而另一个人编写实现。非常干净高效,完全没有“气味”。
    • 我们使用它的另一种情况是,如果我们的类显式实现了一个大型接口,该接口简单地委托给主类上的现有方法。例如,假设我们有一个名为“Foo”的类,其属性为“Count”。 'Foo' 实现了具有 'GetCount' 属性的 'ILaa'。我们将“ILaa”的整个实现(主要是样板代码)移至“Foo.ILaa.cs”,并将“Foo.cs”留给“Foo”的实际实现。如果它是一个较小的界面,我们将它放在 'Foo.cs' 内的一个区域中,无论“Joe Code Horror”说什么,只要使用得当,它就会有效。
    【解决方案2】:

    我必须承认我从未使用过 Objective-C,但当然,我使用过 C#。

    说了这么多,partial classes和classes是一回事,将一个class拆分成多个文件并不会让class变小,只是拆分成文件。 该类的用法将是相同的。

    所以我不同意部分类会解决这个问题,它们主要是为了其他东西而发明的,比如 windows 窗体、wpf、自动生成的代码。 它们在类不能被逻辑拆分但通常应该避免的其他情况下也很有用。

    我认为你应该把你的班级分成几个班级,一个班级在 1k LOC(代码行)之后开始有味道,如果这个班级被分成多个文件。

    使用继承或将类拆分为多个由字段和属性连接的类。 在 chemicalNova 提供的示例中,我会将其拆分为多个类,而不是多个文件。

    【讨论】:

    • 虽然我同意.. 类可以变得这么大,即使在企业解决方案中也是如此。我们可以尽可能地努力,但并不是我们所有的代码都始终如一的“模式与实践”一书中的水准。有时拆分成几个类需要重写整个应用程序.. 这有时是不切实际的。
    • 我是第一个说模式编程不应该被奉为绝对主义宗教或终极真理的人:有案例和案例。然而,允许像上帝类这样的东西是纯粹的邪恶:)
    【解决方案3】:

    我记得当我还是个新手的时候,我们有这个神级“BusinessService”,或者类似的东西。每当有人将其锁定在 TFS 中时,您就会不走运。所以我有了这个绝妙的主意,我们为什么不把它分成部分类。我们最终得到了类似“BusinessService1.cs”..“BusinessService6.cs”的东西。完全是一团糟,找不到东西在哪里完全令人沮丧。

    我认为每次你需要使用部分类,这是一个设计错误。如果 Microsoft 强迫您这样做(wpf、winforms 等)- 这是他们的设计错误。

    【讨论】:

    • 有一些很好的理由使用与生成的代码相关的部分类。你更喜欢旧的#Region 方法?
    • 部分类不是一个错误,感谢微软发明了这一点:) 但正如我所说,它们主要用于自动生成的代码。
    • 在我看来,部分类与区域几乎是一回事。是的,它们之间存在一些技术差异。但它们是解决同一问题的解决方案,而这些问题本来就不应该存在。
    • 我基本上同意你的看法,除了代码生成的情况。 (见我对化学新星的回答)
    【解决方案4】:

    一个很好的参考原则是SOLID principle。特别是“S”代表“单一责任”

    单一责任原则

    一个对象应该只有一个职责的概念。

    当类变得太大时,它们很可能有太多的责任。你能在类的工作范围内定义两个或更多的职责吗?如果是这样,请将其分成两个或更多类。然后,您可以使用 façadecomposite 模式将它们聚合回来。

    换句话说:

    • 你在类中的代码应该根据单一职责原则分成不同的类
    • 原来的God类变成了一个compositefaçade:它使用所有的新类,向系统的其余部分公开相同的方法,但没有实现任何除了将旧式神级调用“转换”成新式 SOLID 调用外,它本身的功能。

    这意味着从面向对象的角度来看,区域完全什么都不做来解决您的问题。事实上,它们实际上会适得其反,因为它们有助于隐藏问题。

    另请参阅这篇 Jeff Atwood 文章:

    http://www.codinghorror.com/blog/2008/07/the-problem-with-code-folding.html

    【讨论】:

    • 假设上帝类的不同职责从不单独使用,当 partial 类(当然是按职责划分)时,为什么更喜欢 Facade 或 Composite东西?
    • 因为您希望您的代码是面向对象的 :-) 上帝类是过程性的,而“部分”类只是类。它是一种语法糖,可让您将源代码拆分为更多文件。有关为什么要面向对象的更多信息,请参见例如eprints.ecs.soton.ac.uk/857/3/html/node3.html
    • 我自己的笔记:这个答案仍然是正确的,或者当然。但是,很多时候,一个巨大的持久对象的解决方案并不是将其分解为 1->1->1-> 关系中的几个较小的对象(Facade 和 Composite 经常是这样的)。事实上,这与使用类别(或部分类)相同......只是隐藏了问题。答案在于动态创建包含数据和行为的对象。毫无疑问,有几种设计模式——比如 ValueObject——可以比我更好地解释我想说的。
    猜你喜欢
    • 1970-01-01
    • 2013-01-24
    • 1970-01-01
    • 1970-01-01
    • 2014-08-18
    • 1970-01-01
    • 2011-02-05
    • 1970-01-01
    • 2018-09-23
    相关资源
    最近更新 更多