2

共通のメソッドを持つ親クラスを作成しましたが、子クラスで実装したいメソッドがあります。つまり、[実行方法] をクリックします。

これを実装する適切な方法は何ですか?

public Parent {
    CancelCommand = new RelayCommand(CancelClicked, CancelCanExecute);
    private void CancelClick(object param) {
        // Do stuff
    }
}

public Child : Parent {
    private bool CancelCanExecute(object param) {
        // Do stuff
        return true;
    }
}

CancelClick は親クラスによってホストされ、CancelCanExecute は子クラスによって処理されます。

外部を使用しますか?または、インターフェイスを使用する必要がありますか? 子クラスでオーバーライドを使用する場合、メソッドを実装する必要はありません。非抽象メソッドなどがあるため、親クラスを抽象に変更する必要があるかどうかわかりません。

4

4 に答える 4

4

したがって、ここにあなたのオプションがあります:

1.基本クラスを宣言しabstract、いくつかのメソッドも宣言します

このアプローチには 2 つの良い点があります。基本クラスで共通メソッドを自由に実装できます (つまり、すべてのメソッドが である必要はありませんabstract)。一方、抽象メソッドは派生クラスでオーバーライドする必要があります。反論点が 1 つあります (ご存知かもしれませんが): インスタンス化することはできません。つまり、次のようなことはできません。

Base obj = new Base();

ただし、これを行うことはできます。

Base obj = new Child();

2.インターフェイスを使用する

クラスにいくつかのメソッドを実装させるために、いくつかのインターフェースを宣言することができます。ただし、継承とインターフェイスのセマンティクスはまったく異なります。どちらが自分に最適かを判断する必要があります。

IMHO、最初のオプションで問題ありません。

于 2012-08-28T17:57:14.053 に答える
3

Parent で抽象メソッドを指定する必要があります。

public abstract class Parent
{
    public void DoSomething()
    {
        // Do something here...
    }

    public abstract void ForceChildToDoSomething();
}

これにより、子はそれを実装するように強制されます。

public class Child : Parent
{
    public override void ForceChildToDoSomething()
    {
        // Do something...
    }
}

ただし、これで抽象的な親が作成されます。したがって、親で機能を使用する場合は、次のようにする必要があります。

Parent parent = new Child();
parent.DoSomething();
parent.ForceChildToDoSomething();
于 2012-08-28T17:58:18.933 に答える
1

インターフェイスを定義してから、コードはそのインターフェイスを実装するオブジェクトのみを受け入れる必要があります。共通の基本クラスを使用して作成することは非常に魅力的ですがabstract、このアプローチは定義上 (ほぼ) 間違っています。

多重継承を許可しない C# やその他の言語では、他のユーザーが埋めなければならない空の「スケルトン」を定義するためだけに基本クラスを作成し、全員にそれを使用させることは非常に制限的です。誰もがそれを継承する必要があるため、たとえば、独自の既存のクラス階層を再利用したり、面倒なブリッジを作成したり (...) する必要はありません。

抽象基本クラスに、1/数/ダース/数百の抽象メソッド、イベント、およびプロパティ以外に何もない場合は、「共通の要件」のみを定義するため、インターフェイスである必要があります。

共通のもので新しい抽象ベースを作成する唯一の合理的な理由は、実際にデフォルトの実装を提供することです。それでも、そのような基本クラスでは、インターフェイスも定義する必要があります。基本はそれを実装し、オーバーライドを許可し、実際には抽象として何かをマークすることさえできますが、コードは基本クラスではなく、インターフェイスを介してすべてを参照する必要があります。このような抽象ベースは、必須ではなく、実装者のヘルプ/ショートカットであるべきです。誰かがゼロからすべてをやりたい場合 - 彼はインターフェイスを実装し、サンプルコードでベースを無視します. それでも、すべての共通コードは、まさにそのインターフェイス上で動作する一連の静的ヘルパー クラスとして提供される場合があります。

抽象基本クラスは実際には必要であり、たとえば、派生クラスにパラメーター付きのコンストラクターを持たせる必要がある場合や、何かから派生する必要がある場合など、いくつかのコーナーケースではインターフェイスに取って代わることはできません。WPF Visual または UIElement または DependencyObject のように --- したがって、Microsoft の設計には、ここでも少し欠陥があります。彼らは基本クラスからの派生を強制し、多くの場所で開発者に影響を与えました (たとえば、EntityFramework のデータ モデル オブジェクトが DependencyObject ではないなど)。それでも、私は彼らがそこから抽象化すべきだったと思います - Visual とその友人を見て、インターフェイスに持ち上げることができなかった多くの内部ルーチンはありません..パフォーマンスについてであり、キャスト/メソッドのディスパッチを削減することでした。

私が言ったことはすべて、あなたが質問で提示したものと正確に一致しないことに注意してください. そこでは、すでに「親/基本クラスが XYZ を処理する」と想定しています。これは、インターフェイス アプローチを最初からやめていることを意味します。インターフェイスでは、クリックとキャンセルクリックが存在する必要があることのみを定義しますが、「基本実装」を強制/提供することはできません。このようなことは、基本クラスで実行できます。したがって、オープン/混合アプローチを採用する必要があると思います。インターフェイスを定義し、静的な再利用可能なハンドラーを定義し、インターフェイスのみを使用し、一部の「怠惰なコーダー」に基本クラスを提供します。

public interface IClickable
{
    ICommand CancelCommand { get; }
    void CancelClick();
    bool CanCancelClick();
}

public static class ClickableDefaultImpl
{
    public static void DefaultCancelClick(IClickable obj)
    {
        ... do the common things on the OBJ
    }
    public static bool DefaultCanCancelClick(IClickable obj)
    {
        ... do the common things on the OBJ
    }
}

public abstract class Clickable : IClickable
{
    public void CancelClick() { ClickableDefaultImpl.CancelClick(this); }
    public bool CanCancelClick() { return ClickableDefaultImpl.CanCancelClick(this);  }
}

これは非常に肥大化しているように見えるかもしれませんが、カスタマイズの余地はかなりあります。オープン性はありますが、全員が「ClickableImpl」を使用する必要があることを強制する方法はほとんどありません。いくつかの方法がありますが、..それらにはさらに肥大化と時間/メモリのオーバーヘッドが含まれます。今説明する価値はないと思います。

将来、誰が、どのように、どのくらいこのコードを使用するかを見積もることを忘れないでください。1 回、2 回、5 回使用する場合は、抽象的なベースを使用してください。しかし、数十または数百の子実装を感知した場合は、少し肥大化したほうがよいでしょう。後で時間を大幅に節約できます。

于 2012-08-28T18:13:09.053 に答える
1

はい、要約:

public abstract Parent
{
  protected abstract bool CancelCanExecute(object param);
  //more stuff
}

である可能性もありますがpublic、そうではありませんprivate

現在、実装していない、CancelCanExecuteまたはそれ自体である派生クラスを持つことはできないabstractため、さらに派生クラスにそれを実装するよう強制します。

于 2012-08-28T17:59:55.797 に答える