何时将公共字段移入基类?


16

我目前有两个派生类AB,它们都有一个共同的字段,并且我试图确定它是否应该进入基类。

永远不会从基类中引用它,并且说如果在将来的某个时刻派生出另一个没有的类C,那么它不会_field1违反“最低特权”(或某些东西)的原则。是吗

public abstract class Base
{
    // Should _field1 be brought up to Base?
    //protected int Field1 { get; set; }
}

public class A : Base
{
    private int _field1;
}

public class B : Base
{
    private int _field1;
}

public class C : Base
{
    // Doesn't have/reference _field1
}

18
我认为这个问题是不清楚,因为你没有给我们带来什么任何想法BaseABC,和_field1是。这些都是重要的细节,不应忽略;我认为您应该编辑问题以讨论这些内容。
Tanner Swett

根据答案,我将:重建Vehicle以具有虚拟悬架,然后Car和Bicycle可以具有Wheels和Boat可以具有浮力,这将使抽象向上移动。我发现,如果我的抽象直接导致特定的设置,那么我还没有把这个概念推到足够高的水平。
Patrick Hughes

6
不要使用类继承来避免重复代码。使用它来继承和扩展行为,即多态。当且仅当在逻辑上相同的字段(而不是两个不相关的信息,恰巧在各自的上下文中共享相同的名称)时,才将公共字段移动到基类。
布兰登

为什么要有一个基础课呢?
jpmc26

Answers:


34

这完全取决于您要解决的确切问题。

Consider a concrete example: your abstract base class is Vehicle and you currently have the concrete implementations Bicycle and Car. You're considering moving numberOfWheels from Bicycle and Car to vehicle. Should you do this? No! Because not all vehicles have wheels. You can already tell that if you try to add a Boat class then it's going to break.

现在,如果您的抽象基类是,WheeledVehiclenumberOfWheels在其中具有成员变量是合乎逻辑的。

您需要对问题应用相同的逻辑,因为如您所见,这不是简单的是或否答案。


3
可以暂时接受0是有效的车轮数。但是,最终您可能会添加一个roll()方法,此时子类的想法看起来是有先见之明的。
user949300

11
船上有0个轮子。这有什么坏处?
D Drmmr

14
@DDrmmr不是船有0个轮子,而是轮甚至不存在作为船的概念-因此您的模型不应该允许它。
彼得M,

10
我的观点是这个例子很糟糕。车辆(碰巧是船)在理论上没有错,它的车轮为0。
D Drmmr

10
然后,当您需要存放明轮船时,一切就变得地狱了。
IllusiveBrian19年

13

从逻辑上讲,除了将要复制的字段放在基类中,而不是将基类中的公共字段放置在基类中之外,还有第三种选择:将新的子类引入具有两者之间公共属性的层次结构中。@Pete在没有完全去那里的情况下暗示了这一点。

使用@Pete的示例,我们将为Wheeled Vehicle引入一个(可能是抽象的)子类,该子类从原始基类继承而来,而两个子类则从其继承。因此,原始基类不会受到轮子的污染,但是轮子的共性是DRY(在具有轮子的子类中不会重复)。

当然,出于您的目的,这可能是过大的,但是类层次结构机制对此提供了支持。


这实际上是我决定要做的(A和B大多数重叠,因此B将从A派生)。
samis

9

我要在这里扮演魔鬼的拥护者。

现在你什么都不做。

干吗?不能。但是最好有一些重复,而不是过早的抽象,而稍后又不容易退出。将属性移动到通用基类的重构很容易。走另一条路不是。等着瞧。

当做出这样的决定时,我倾向于使用“ 3规则”:一旦我在三个不同的地方重复了相同的事情,只有到那时,我才考虑将其向上移动。注意,您只有2岁。


2
我要说,做出决定需要明智的观察。
–radarbob

1
我大都同意,但是“立即”(没有多余的代码,如我们所见)在两个方向上的重构都是微不足道的。但是,如果还有其他代码使用该字段,则双向重构可能会变得非常困难。
布朗

2

通常,我会将其移至基类。我认为没有客观的是/否,因为这里需要权衡取舍-携带未使用的字段与降低复杂性。

我通常更喜欢包含任何可能共享的“重载”基类。由于不需要每个派生类中的后代序列化方法,因此这使得序列化到文件更加简单。但是,如果没有这个问题或类似问题,或者您可能需要尽一切可能减少内存使用,那么仅将字段保留在需要的地方就可以了。

如果您的字段数量非常有限,则介绍公共字段的“中间”类会很好。但是请注意,如果您有数十个字段以不同的组合使用,则此方法会大大增加复杂性,从而导致许多中介类各自引入一组特定的字段。这可能会成为维护问题。


我的示例很简单,尽管它仍然是生产代码。您提出了一个很好的论据,以“沉重”的基类“损害”层次结构,在这种情况下,我也将看到自己的倾向。
samis

1
@samis:您使用的名称为“ A,B,C”和“ Base”的类只有一个字段,生产代码中没有方法?我对此表示怀疑。
布朗
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.