2010-11-26 4 views
3

サブクラスで値(Value)をオーバーライドする必要があるベースクラス(下の例ではMyBase)を使用している場合、これを実装する方法がありますか?私はそれを行ういくつかの方法を考えることができますが、なぜ私が別のものを選択するのかについての感触はあまりありません。私はいくつかの例を持っています(C#では、どんなOO言語でもあります)。OOプログラミングスタイル - 仮想プロパティ、コンストラクタパラメータ、または保護されたセッタ

基本クラスの具体的なプロパティ - サブクラスは必要に応じてこの値を設定できます。

public class MyBase 
{ 
    protected string Value { get; set; } 

    protected MyBase() 
    { 
     Value = "Default Value"; 
    } 

    private DoSomethingWithValue() 
    { 
     Console.WriteLine(Value); 
    } 
} 

public class MySub : MyBase 
{ 
    public MySub() 
    { 
     Value = "Overridden Value"; 
    } 
} 

仮想プロパティ - 彼らが望むなら、サブクラスでこのメソッドをオーバーライドすることができます。

public class MyBase 
{ 
    protected virtual string Value { get { return "Default Value"; } } 

    protected MyBase() 
    { 
    } 

    private DoSomethingWithValue() 
    { 
     Console.WriteLine(Value); 
    } 
} 

public class MySub : MyBase 
{ 
    protected override string Value { get { return "Overridden Value"; } } 

    public MySub() 
    { 
    } 
} 

プロパティは、基本クラスのコンストラクタに設定 - サブクラスは、値を提供することができます。

public class MyBase 
{ 
    protected string Value { get; private set; } 

    protected MyBase(string value) 
    { 
     Value = value; 
    } 

    protected MyBase() : this("Default Value") 
    { 
    } 

    private DoSomethingWithValue() 
    { 
     Console.WriteLine(Value); 
    } 
} 

public class MySub : MyBase 
{ 
    public MySub() : base("Overridden Value") 
    { 
    } 
} 

明らかに、これらの値の一部は値を変更したり動的に計算したりすることができます。しかし、コンパイル時にその値がわかっている状況では、どちらの方法が望ましいのですか?その理由は何ですか?

答えて

0

潜在的な派生クラスのすべてについてコンパイル時に値が分かっている場合、実行時にその値を保存するのはなぜですか?

さらに重要なことに、仮想ルックアップを呼び出すのは、すべてがreturn "constant";であることがわかっているので、ここで仮想ルックアップを呼び出すのは無駄だから、ベースの具体的なプロパティに行きます。

+0

+1最も簡単な解決策を使用してください – Nobody

+0

私はあなたの答えに従うとは思わない - 「実行時には保存しない」と言って、基本クラスに具体的なプロパティが必要だと言う。 (コンストラクタまたは基本クラスのコンストラクタでそれを割り当てます)。 –

-1

すべてのオブジェクト指向の意味を無視し、パブリックデータメンバーを持つ簡単な構造から始めます。これは、最小限の作業であり、理解しやすく、使いやすく、最も強力です。使用のコンテキストをよく理解し、クラスが抽象を実際に表していることを確認したら、控えめな制限を適用し、コードがどこで壊れているかを注意深く観察してください。

何十年もの重い数学によって裏付けられた絶対的な証拠がない限り、ではなく、は最初抽象を使用します。クライアントからの表現を分離する前に、抽象概念が健全で完全であることを完全に確信しなければなりません。アサーションまたは少なくともコメントで、表現の不変条件を明記してください。これを行うことができない場合、抽象を作成するのに十分理解していません。例えば

(C++で、申し訳ありません):あなたは、たとえば、追加を実装する場合は特に表現の不変性を確保する計算コストは​​、保存されていることに注意すべきである。この特定のケースで

class Rational { 
    int numerator; int denominator; 
public: 
    Rational (int x, int y) { 
    if (y == 0) { throw DivisionByZero; } 
    assert (y != 0); 
    if (y<0) { x = -x; y = -y; } 
    assert (y>0); 
    int d = gcd(x,y); 
    assert(d>0); // proof, from specs of gcd 
    // assert: if there exists an integer q>0 which divides both x/d and y/d 
    // then q == 1 (from definition of gcd) 

    assert (x % d == 0); // d divides x exactly (from defn of gcd) 
    assert (y % d == 0); // d divides y exactly (from defn of gcd) 

    numerator = x/d; 
    denominator = y/d; 

    // assert: provided y != 0, numerator/denominator (math div, not C div) 
    // equals input x/ input y (math div, not C div). 

    // invariant: denominator > 0, gcd (numerator, denominator) == 1 
    // Theorem: representation is unique 
    } 

    bool eq(Rational other) { 
    numerator == other.numerator && denominator == other.denominator; 
    // sufficient by uniqueness theorem 
    } 
}: 

。おそらく、これは良い考えではないでしょう。インターフェイスはどのように見え、どのように使用するかによって異なります。不変量を保存することは、計算上有用な性質を1つ持ち、乗算の回避可能なオーバーフローを防ぎます。この場合

は表現は、次のタイプと、標準的な標準形式である:

R: int * int - { x,y | y<0 or Exists d. d divides y and d divides x } 

それは表現が、セットRを生成する直積マイナスサブセットからなることが、一般的であるように

R < ==>

ここで、Aは抽象型であり、bijectionです。

私の主張:抽象化権を得るのはあまり簡単ではありません。プログラマは、例えば、デカルト製品である単純な構造が、形式的には抽象的な(この場合は関数で表される)抽象的な形であることを知らないときに、クラスのようなデバイス、特にOO言語を生成する強い抽象を濫用する。

欠陥のある抽象化を修復することは、単純な構造を使用し、それがリファクタリングフェーズで系統的に抽象化されている場合よりも、クラスのインタフェースだけでなく、抽象化が本当にすべきであるものの

イットリルのルール:抽象化を考えている場合は...

あなたには証拠は必要ありません。

+0

この質問は本当にこの答えですか? –

+0

はい、質問が間違っていることを示しています。 OPは何かの必要性を前提としており、答えは必要ではないだけでなく、実際には望ましくないということです。 – Yttrill

+0

私は何の必要性を前提にしていますか? –

関連する問題