1

次のような WidgetBase という抽象基本クラスがあります。

public abstract class WidgetBase : Control, INamingContainer
{
     // This class declares abstract and virtual properties and methods but doesn't override anything
}

次のような ScrollerBase という別の抽象基本クラスがあります。

public abstract class ScrollerBase : Control
{
    // This class has one abstract property and overrides OnInit and OnLoad
}

これらの両方のクラスを継承するクラスを作成する必要があります。どちらのクラスもインターフェイスに変換できません。私が考えることができる最も簡単な解決策は、次のような追加の WidgetBase クラスを作成することです。

public abstract class ScrollingWidgetBase : ScrollerBase, INamingContainer
{
     // Lots of duplicated code from WidgetBase
}

次のようなことができればいいのですが。

public abstract class ScrollingWidgetBase : WidgetBase<ScrollerBase>    { /* Empty */ }
public abstract class WidgetBase : WidgetBase<Control>    { /* Empty */ }
public abstract class WidgetBase<T> : T, INamingContainer    { /* Code goes here */ }

ただし、これは不可能です。私が考えることができる唯一の半分エレガントなソリューションは、次のようなものです。

public interface IScroller { /* Overridable members go here */ }
public class WidgetBase : Control, INamingContainer
{
    protected override void OnInit(EventArgs e)
    {
        if (this is IScroller)
        {
            // Do scroller logic here
        }
    }
    protected override void OnLoad(EventArgs e)
    {
        if (this is IScroller)
        {
            // Do scroller logic here
        }
    }
}

public class Test : WidgetBase, IScroller {  }

ただし、より多くのクラスが作成されると、これは非常に面倒になります。確かに、この問題を解決する何らかの設計パターンがあるはずですか? どんな助けでも大歓迎です。

ありがとう、

ジョー

4

4 に答える 4

4

hyde が言ったように、実際には自分の振る舞いをクラスと切り離す必要があります。あなたはインターフェースを使いたくないと言った。まあ、それを回避する方法は考えられません。弾丸を噛むか、コードの複製を行う必要がある場合があります。

最低限、動作ロジックを別の制御クラスに移動し、必要なメンバーを公開するインターフェイスを単純にフィードすることができます。スクロール可能な UI コントロールに必要ないくつかのプロパティを考えてみましょう(注意してください、これはすべて単なる例です。説明したようにこれらの型が存在するとは思えないか、実際に必要な最小限のセットです)。

public interface ISCrollable
{
    Control Target { get; }
    ScrollBar Bar { get; }
    double FullLength { get; }
    double VisibleLength { get; }
}

次に、スクロール動作を、その動作をアタッチするか、次の要素で動作するクラスに配置できますIScrollable

public class Scroller
{
    public Scroller(ISCrollable scrollable)
    {
        //attach behaviour
        scrollable.Bar.OnClick += DoScroll;
        //and other stuff
    }
}

最後に、あなたScrollableWidgetはあなたのものにControlなり、スクロール動作を継承するのではなくアタッチします:

public class ScrollableWidget : Control, INamingContainer, ISCrollable, IWidget
{
    private Scroller ScrollBehaviour;
    private Widgeter = WidgetBehaviour;

    public Control Target { get; private set; }
    public ScrollBar Bar { get; private set; }
    public double FullLength { get; private set; }
    public double VisibleLength { get; private set; }

    public ScrollableWidget()
    {
        this.Target = this;
        this.Bar = CreateScrollBarControl();
        this.FullLength = 9001;
        this.VisibleLength = this.ActualHeight;

        this.ScrollBehaviour = new Scroller(this);
        this.WidgetBehaviour = new Widgeter(this);
    }
}

そうです、あなたはインターフェースを使いたくなるでしょう。しないというあなたの要件がわかりません。Decoratorなど、私が投稿したばかりの混乱よりも適している可能性がある他のパターンがあります。

于 2012-10-11T13:14:15.270 に答える
0

なんらかの理由でScrollerBase継承するように変更できないと思います。WidgetBaseそれは本当に最良の解決策でしょう。

それができない場合は、拡張メソッドとインターフェースを組み合わせることで、多重継承のようなものを実現できます。

public interface IWidgetBase
{
  bool SomeBool { get; }
  void DoWidgetyStuff();
}
public static class IWidgetBaseExtensions
{
  public static void WidgetStuff(this IWidgetBase base)
  {
    if (base.SomeBool) 
      base.DoWidgetyStuff();
  }
}


public class ScrollerBase : Control, IWidgetBase
{
  public bool SomeBool { get; protected set; }
  public void DoWidgetyStuff() {
    // Do stuff
  }
}

// Main code:
IWidgetBase myScroller = new ScrollerBase();
myScroller.WidgetStuff();

コードの実行内容に応じて、これは他の人が提案した構成よりも良い答えである場合とそうでない場合があります。

于 2012-10-11T13:38:46.193 に答える
0

古い原則が適用されます: 継承より合成。

クラスが実際に基本クラスとして機能する必要がない限り、継承しないでください。代わりに、基本クラスになる予定のクラスを派生クラスになる予定のメンバーとして配置します。

クラスの代わりにインターフェイスをメソッド パラメーターの型などとして使用すると、継承の代わりに構成を実際に使用できます。

コンポジションを使用する場合は、IDE のリファクタリング機能を使用してメンバー オブジェクトのデリゲート メソッドを挿入する方法を学びます。

于 2012-10-11T13:03:40.263 に答える
0

私が正しく理解していれば、スクローラーはウィジェットのデコレーターです。

1) インターフェイス IWidgetBase を作成します。

2) デコレータを実装する

class ScrollDecorator:IWidgetBase{
   IWidgetBase _decoratedWidget;
   public ScrollDecorator(IWidgetBase widget){
       _decoratedWidget=widget;
   }
   //implementation  
}
于 2012-10-11T13:14:13.423 に答える