変更できないクラスにポリモーフィックな動作を実装する最良の方法は何ですか? 現在、次のようなコードがあります。
if(obj is ClassA) {
// ...
} else if(obj is ClassB) {
// ...
} else if ...
明らかな答えは、基本クラスに仮想メソッドを追加することですが、残念ながらコードは別のアセンブリにあり、変更できません。上記の醜くて遅いコードよりも、これを処理するためのより良い方法はありますか?
変更できないクラスにポリモーフィックな動作を実装する最良の方法は何ですか? 現在、次のようなコードがあります。
if(obj is ClassA) {
// ...
} else if(obj is ClassB) {
// ...
} else if ...
明らかな答えは、基本クラスに仮想メソッドを追加することですが、残念ながらコードは別のアセンブリにあり、変更できません。上記の醜くて遅いコードよりも、これを処理するためのより良い方法はありますか?
うーん... Adapterの方が適しているようです。
public interface ITheInterfaceYouNeed
{
void DoWhatYouWant();
}
public class MyA : ITheInterfaceYouNeed
{
protected ClassA _actualA;
public MyA( ClassA actualA )
{
_actualA = actualA;
}
public void DoWhatYouWant()
{
_actualA.DoWhatADoes();
}
}
public class MyB : ITheInterfaceYouNeed
{
protected ClassB _actualB;
public MyB( ClassB actualB )
{
_actualB = actualB;
}
public void DoWhatYouWant()
{
_actualB.DoWhatBDoes();
}
}
大量のコードのように見えますが、これにより、クライアント コードが必要なものにかなり近くなります。さらに、実際に使用しているインターフェイスについて考える機会を与えてくれます。
訪問者パターンを確認してください。これにより、クラスを変更せずに仮想メソッドをクラスに追加することができます。使用している基本クラスに Visit メソッドがない場合は、動的キャストで拡張メソッドを使用する必要があります。サンプルコードは次のとおりです。
public class Main
{
public static void Example()
{
Base a = new GirlChild();
var v = new Visitor();
a.Visit(v);
}
}
static class Ext
{
public static void Visit(this object b, Visitor v)
{
((dynamic)v).Visit((dynamic)b);
}
}
public class Visitor
{
public void Visit(Base b)
{
throw new NotImplementedException();
}
public void Visit(BoyChild b)
{
Console.WriteLine("It's a boy!");
}
public void Visit(GirlChild g)
{
Console.WriteLine("It's a girl!");
}
}
//Below this line are the classes you don't have to change.
public class Base
{
}
public class BoyChild : Base
{
}
public class GirlChild : Base
{
}
Decoratorパターンを見てください。ノルドリンはパターンの名前を出さずに実際に説明しました。
デコレーターは、継承せずに動作を拡張する方法です。Noldorin のコードで変更する唯一の点は、コンストラクターが、装飾しているオブジェクトのインスタンスを受け取る必要があるという事実です。
ここでの標準的なアプローチは、保護されたインスタンス変数として「継承」するクラスをラップし、ラップされたクラスのすべての非プライベート メンバー (メソッド/プロパティ/イベント/など) をコンテナー内でエミュレートすることです。クラス。次に、このクラスとその適切なメンバーを仮想としてマークして、標準のポリモーフィズム機能を使用できるようにします。
これが私の言いたいことの例です。ClosedClass
アクセスできないコードを持つアセンブリに含まれるクラスです。
public virtual class WrapperClass : IClosedClassInterface1, IClosedClassInterface2
{
protected ClosedClass object;
public ClosedClass()
{
object = new ClosedClass();
}
public void Method1()
{
object.Method1();
}
public void Method2()
{
object.Method2();
}
}
参照しているアセンブリが適切に設計されていれば、アクセスする可能性のあるすべての型/メンバーが適切に (抽象、仮想、封印) マークされますが、残念ながらそうではありません (これを経験することさえあります)。 Base Class Library の問題)。私の意見では、ラッパー クラスはここに行く方法です。クラスのユーザーにアクセスさせたくないメソッドの修飾子を削除/変更するという利点があります(派生元のクラスが継承可能な場合でも)。ReadOnlyCollection<T>
BCL の は、この良い例です。
拡張メソッドは、既存のクラスにメソッドシグネチャを追加する簡単な方法を提供します。これには3.5フレームワークが必要です。
静的ユーティリティクラスを作成し、次のようなものを追加します。
public static void DoSomething(this ClassA obj, int param1, string param2)
{
//do something
}
ページにユーティリティクラスへの参照を追加すると、このメソッドはClassAのメンバーとして表示されます。この方法で、既存のメソッドをオーバーロードしたり、新しいメソッドを作成したりできます。