1

ハードウェア アクセサリのユーザー インターフェイスを作成しているとします。アクセサリには、Widget Lite と Widget Pro の 2 つのバージョンがあります。

Widget Pro は、Widget Lite ができるすべてのことを実行できますが、さらにいくつかのオプションがあり、Widget Lite ができないいくつかのことを実行できます。もっと詳しく言えば、Widget Lite には 1 つのチャンネルがあり、Widget Pro には 2 つのチャンネルがあるため、ボリューム コントロールに類似したものになると、Lite では 1 つのコントロールだけで済みますが、Pro では 2 つのコントロールで独立したコントロールが可能です。

これを処理するアプリケーションを構築する最初の試みで、Widget Pro を表すクラスに Widget Lite を拡張させましたが、その後、醜いように見える違いを処理するためのあらゆる種類の条件付きケースになってしまいました。このような状況に役立つ適切なデザインパターンを知っている人はいますか? 私の想像力は、私の検索に役立つ同義の状況を思いつくのに空白を描いています.

4

4 に答える 4

2

まず、プラグインパターン(依存性逆転の形式の1つ)を確認します。

LiteバージョンとProバージョンに共通のインターフェイスを抽象化してみてください。

interface IBaseWidget
{
   IControl CreateVolumeControl();
   // ... etc
}

別々のアセンブリ/dllで、LiteウィジェットとProウィジェットを実装します。

class LiteWidget : IBaseWidget
{
   int _countCreated = 0;
   IControl CreateVolumeControl()
   {
       _countCreated++;
       if (_countCreated > 1)
       {
          throw new PleaseBuyTheProVersionException();
       }
   }
}

LiteデプロイメントでProバージョンを配布したくないので、実行時にdllをロードする必要があります。たとえば、コンベンション(たとえば、ベースアプリが* Widget.dllという名前のDLLを探し回る)または構成によって、これは、の適切な具体的な実装を見つけIBaseWidgetます。@Bartekのコメントによると、理想的には、ベースエンジンクラスファクトリがの特定の具象クラスについて「知っている」ことを望まないでしょうIBaseWidget

于 2012-08-29T09:43:42.933 に答える
1

訪問者パターンが役立つ場合があります。dofactoryを確認してください。

ビジタークラス...

...オブジェクト構造内の ConcreteElement の各クラスに対して Visit 操作を宣言します。操作の名前と署名は、Visit リクエストを訪問者に送信するクラスを識別します。これにより、訪問者は、訪問されている要素の具体的なクラスを決定できます。その後、訪問者は特定のインターフェースを介して要素に直接アクセスできます

これは、Vikdor が語った抽象クラスの実装に似ています。

これについての wiki リンクは次のとおりです

ビジター パターンには、単一のディスパッチとメソッドのオーバーロードをサポートするプログラミング言語が必要です。

WidgetLite と Pro のさまざまなチャネルと音量設定の要件に対して、訪問者パターンを使用して非常に単純な実装を提供しました。コメントで、ビジター パターンが if-else 呼び出しを減らすのに大いに役立つことを述べました。

基本的な考え方は、コントロール (ボリュームなど) をウィジェットに渡すことであり、ウィジェットは必要に応じてそれを使用する方法を認識します。したがって、コントロール オブジェクト自体の実装は非常に単純化されています。各ウィジェットのコードは一緒です!!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WidgetVisitor
{
    //This is the widget interface. It ensures that each widget type
    //implements a visit functionality for each control. The visit function
    //is overloaded here.
    //The appropriate method is called by checking the parameter and this 
    //avoids the if-then logic elegantly
    public interface Widget
    {
        void visit(Volume vol);
        void visit(Channel chan);
        void Display(AllControls ac);
    }

    //This is the interface which defines the controls. Each control that 
    //inherits this interface needs to define an "accept" method which 
    //calls the appropriate visit function of the right visitor,
    //with the right control parameter passed through its call!
    //This is how the double dispatch works.
    //Double dispatch: A mechanism that dispatches a function call to different concrete 
    //functions depending on the runtime types of two objects involved in the call.
    public interface WidgetControls
    {
        void accept(Widget visitor); 

    }

    //I have implemented the volume control and channel control
    //Notice how the code for defining each control is the SAME
    //in visitor pattern! This is double dispatch in action
    public class Volume : WidgetControls
    {
        public int volLevel { get; set; }
        public int volJazz { get; set; }
        public int volPop { get; set; }
        public void accept(Widget wc)
        {
            wc.visit(this);
        }
    }

    public class Channel : WidgetControls
    {
        public int channelsProvided { get; set; }
        public int premiumChannels { get; set; }
        public void accept(Widget wc)
        {
            wc.visit(this);
        }
    }

    //Widget lite implementation. Notice the accept control implementation
    //in lite and pro.
    //Display function is an illustration on an entry point which calls the
    //other visit functions. This can be replaced by any suitable function(s)
    //of your choice
    public class WidgetLite : Widget
    {
        public void visit(Volume vol)
        {
            Console.WriteLine("Widget Lite: volume level " + vol.volLevel);
        }

        public void visit(Channel cha)
        {
            Console.WriteLine("Widget Lite: Channels provided " + cha.channelsProvided);
        }

        public void Display(AllControls ac)
        {
            foreach (var control in ac.controls)
            {
                control.accept(this);
            }

            Console.ReadKey(true);
        }
    }

    //Widget pro implementation
    public class WidgetPro : Widget
    {
        public void visit(Volume vol)
        {
            Console.WriteLine("Widget Pro: rock volume " + vol.volLevel);
            Console.WriteLine("Widget Pro: jazz volume  " + vol.volJazz);
            Console.WriteLine("Widget Pro: jazz volume  " + vol.volPop);
        }

        public void visit(Channel cha)
        {
            Console.WriteLine("Widget Pro: Channels provided " + cha.channelsProvided);
            Console.WriteLine("Widget Pro: Premium Channels provided " + cha.premiumChannels);
        }

        public void Display(AllControls ac)
        {
            foreach (var control in ac.controls)
            {
                control.accept(this);
            }

            Console.ReadKey(true);
        }
    }

    //This is a public class that holds and defines all the 
    //controls you want to define or operate on for your widgets
    public class AllControls
    {
        public WidgetControls [] controls { get; set; }

        public AllControls(int volTot, int volJazz, int volPop, int channels, int chanPrem)
        {
            controls = new WidgetControls []
            {
                new Volume{volLevel = volTot, volJazz = volJazz, volPop = volPop},
                new Channel{channelsProvided = channels, premiumChannels = chanPrem}
            };
        }
    }

    //finally, main function call
    public class Program
    {
        static void Main(string[] args)
        {
            AllControls centralControl = new AllControls(3, 4, 2, 5, 10);

            WidgetLite wl = new WidgetLite();
            WidgetPro wp = new WidgetPro();

            wl.Display(centralControl);
            wp.Display(centralControl);

        }
    }
}
于 2012-08-29T09:50:30.250 に答える
0

私はそれを次のようにします:

              AbstractWidget (Abstract class)
                   /\
                  /  \
                 /    \
                /      \
               /        \
         WidgetLite   WidgetPro

共通のコードはAbstractWidget(インスタンス化されるべきではないため抽象的)に入り、これら2つのクラス間で異なる動作は具象クラスに入ります。

于 2012-08-29T09:27:30.333 に答える
0

と の両方から派生する基本Widgetクラスを用意することを強くお勧めします。Widget LiteWidget Pro

public class Widget {}

public class WidgetLite : Widget {}

public class WidgetPro : Widget {}

Pro両方とLite基本クラス内で共有されるプロパティ/メソッドを持っています。これはあなたにとってよりクリーンなデザインです。

于 2012-08-29T09:26:25.193 に答える