2009-11-04 115 views
4

从具体子类中抽象类中提供值的“正确”方式是什么?从子类中提供抽象类成员变量

即,我应该这样做:

abstract class A { 
    private string m_Value; 

    protected A(string value) { 
     m_Value = value; 
    } 

    public string Value { 
     get { return m_Value; } 
    } 
} 

class B : A { 
    B() : this("string value") {} 
} 

或本:

abstract class A { 

    protected A() { } 

    public abstract string Value { get; } 
} 

class B : A { 
    B() {} 

    public override string Value { 
     get { return "string value"; } 
    } 
} 

或其他什么东西?

如果仅在抽象类中使用Value属性,应该做不同的事情吗?

回答

1

我通常更喜欢第一种方法,因为它需要较少的子类代码。

但是,我承认第二种方法的语义更加清晰细腻。覆盖属性说“这个属性的实现是我的身份的一部分。”传递构造函数参数具有不同的含义:“我为这个其他的东西设置了一个值,这恰好是我的基类。”它意味着构成(has-a)而不是继承(is-a)。

如果 Value属性只在 抽象类应使用不同的东西做什么?

在这种情况下,您应该使用第一种(基于构造函数的)方法,以便您可以从子类中隐藏该实现细节。

同样,如果您需要使用构造函数中的值;作为Marc mentioned这是使用第一种方法的实际技术原因。虽然在这种特定情况下无关紧要,但如果稍后某人修改了属性重写以在派生类中使用某些其他成员变量,那么您可能手上有一个微妙的错误。

1

这取决于;基地级需要在ctor中了解它吗?如果是这样,override的做法可能是一个坏主意(virtual在ctor内部不能很好地工作)。否则,任何一个都可以。

1

我认为第二个习语更好,因为它更易于管理(如果您的基类需要派生类中定义的多个属性,构造函数会变得杂乱)。信息来源的地方也更清楚。如果您看到Value属性,那么您知道它是在子类中定义的。在第一个示例中,您必须跟踪m_Value变量的定义点,该变量可以在基类中修改。

1

我认为它几乎是一样的,选择一种方式,并坚持一致。

这两个解决方案都迫使派生类提供一个值,这是很好的;一种可能的替代,如果不应该要求一个值:

abstract class A { 
    public string Value { 
     get; 
     protected set; 
    } 
} 

我个人的偏好是您的第一选择(构造函数参数),因为我个人认为它是更清晰的一个,但它是真正的喜好问题。

1

这取决于。

如果我需要修改抽象类中的Value,我将使用第一种方法。

只有当我需要从A和某处继承很多类时,才会使用第二种方法,我需要将继承的类装箱到基本抽象类。

如果上述两个都不正确,我将使用第二种方法,它更易于管理和清洁。

如果Value仅用于抽象类,我将声明它为private而不是属性。

0

第二种情况的一个主要优点是它允许子类为Value属性定义行为,该属性可能比简单的标量值更复杂。例如,您可能想根据子类定义的其他字段来计算值。采用第一种方法,这是不可能的,但第二种方法允许这样做。

+0

您可以通过声明虚拟属性来实现第一种方法。 – 2009-11-04 16:49:30

0

我更喜欢第二个。如果值是常量或者可以在运行时计算,它可以让您提供一个值,而无需向类中添加实际字段。您拥有的状态越少(字段越少),您可能会发现该代码的可维护性越高。