Answers:
实例变量过多与复制代码没有直接关系,反之亦然。一般而言,该陈述是错误的。一个人可以将两个没有重复代码的单独的类扔到一个类中,这将产生一个新的类,该类具有单独的职责和太多的实例变量,但仍然没有重复的代码。
但是,当您发现一个类在现实世界中的遗留代码中职责过多时,编写该类的程序员很可能不关心纯净代码或SOLID原理(至少在他编写该代码时并不在意),因此您会在其中发现其他代码气味,例如重复代码。
例如,“复制粘贴重用”反模式通常是通过复制旧方法并对其进行一些细微修改而没有适当的重构而应用的。有时,要使此工作有效,就必须复制一个成员变量并对其进行一些修改。这可能会导致类中包含太多实例变量(更精确的是:太多看起来非常相似的实例变量)。在这种情况下,相似的实例变量可能是该类中其他位置重复代码的指示符。但是,正如您所指出的,这是一个人为的示例,因此我不会从中得出一般规则。
实例变量过多意味着状态过多。状态太多会导致重复的代码,对于每个状态而言,它们只是稍有不同。
这是经典的单一具体类,做了太多应该是子类或合成的事情。
找到一些实例变量太多的类,您会发现它们维护了太多的状态,并且有很多重复的代码路径,每种情况只针对这些情况进行了专门的处理,但是它们是如此复杂以至于无法将它们分解为可重用的方法。这也是最大的来源之一side effects
。
对此至少有一个例外,它不属于此类别,并且是补救此问题的简便方法。Immutable
对象不存在此问题,因为它们是固定状态,所以没有任何可能出现混乱状态管理或副作用的机会。
您引用的陈述旨在在特定的上下文中显示。
根据我的经验,我无法确认“许多实例变量通常表示重复的代码”。另外,请注意,这属于“代码气味”,并且据称存在相互矛盾的气味。在这里看看:
http://c2.com/cgi/wiki?CodeSmell
有趣的是,您会发现“实例变量太多”和“实例变量太少”一样好。
但是实例变量存在问题,无论是太少还是太多:
每个实例变量可能意味着对象的某种状态。斯塔蒂总是需要仔细的治疗。您必须确保已涵盖所有可能的stati组合,以避免意外行为。您现在必须始终清楚:我的对象现在处于哪种状态?从这个角度来看,许多实例变量可能表明该类已变得不可维护。这也可能表明一个班级需要做很多工作,因为它需要太多的工作。
每个实例变量都需要您进行监督,哪些方法会以何种方式更改变量。因此,突然之间,您不再知道所有正在做饭的厨师。其中之一,在深夜很累的编程,会破坏你的汤。再次:这样的变量太多会导致代码难以渗透。
另一方面:实例变量太少可能导致许多方法必须处理太多工作和太多参数的信息。如果您给许多方法一个相等的参数,并且所有方法对此参数做某种非常相似的事情,您就会感觉到。在这种情况下,您的代码将开始膨胀。您最终将向上和向下滚动许多屏幕,以便将一些简单的内容组合在一起。在这里,重构可能会有所帮助:引入一个实例变量和一个明确的入口。然后,释放所有方法。
最后但并非最不重要的一点:如果一个类的许多实例变量每个都有其setter和getter,则可能表明其他类没有以正确的方式使用第一个类。关于“ 为什么吸气剂和塞特器是邪恶的 ”的讨论。简而言之,想法是,如果一个类Rectangle
提供了getX()
,而其他几十个类则使用rectangle.getX()
,那么您正在编写的代码对于“涟漪效应”是不稳健的(代码更改影响其他代码的程度有多大)。只需问一下将类型从更改int
为会double
怎样?根据讨论,rectangle.getX()
实际上许多呼叫应该更好地像rectanlge.calculateThisThingForMe()
。因此,非常间接地,许多实例变量中可能会出现重复的代码,因为周围的许多类都使用许多getter和setter来做非常相似的事情(即复制的事情),因此最好在类内移动它们。
许多或很少的实例变量仍然是一个永久的权衡,随着软件的发展,这两种方式都会改变。
简而言之:代码中关注点分离不良,导致代码不是模块化的,导致不良复用,导致代码重复。
如果您从不尝试重复功能,则不会得到重复的代码,并且许多实例变量也不会成为问题。
如果您确实尝试重复功能,那么非模块化的整体代码将无法重用。它做得太多,只能做它做的事情。要执行相似但不相同的操作,剪切和粘贴而不是破坏整体代码“更容易”。经验丰富的程序员知道,重复的代码是通往地狱的道路。
因此,尽管许多实例变量本身不是问题的根本原因,但强烈的“气味”表明问题即将来临。
语言“不能落后”比说“必须遵循”要弱,因此作者并没有声称它必须发生,但最终会发生。如果您需要重用功能,但是不能使用,因为代码不是模块化的。
n
布尔变量例如创建一个内部状态空间2^n
。尽管您的对象通常没有那么多可观察的状态,但是由于您将所有状态都塞入了一个对象中,因此内部仍然需要处理所有这些状态。