訪問者パターンが役立つ場合があります。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);
}
}
}