質問
私は、2つの名前空間でほぼ重複したコードを提供するWebサービスを使用しています。たとえば、PigFeetとHorseFeetの場合、両方の名前空間にFeetクラスが含まれており、Feetクラスで動作する他のコードでは、同じ名前空間の一部である必要があります。
今すぐ私のコードでは、次のようなことを強制されています:
if( _animalType == AnimalType.Pig )
{
//namespace is pigfeet
PigFeet.Feet feet = new Feet();
feet.WashFeet();
}
if( _animalType == AnimalType.Horse )
{
//namespace is horsefeet
HorseFeet.Feet feet = new Feet();
feet.WashFeet();
}
これにより、重複したコードが大量に残ります。名前空間をより動的に選択する方法はありますか?
解決
名前空間は問題ではありません-2つのクラスが関連していないというだけなので、ポリモーフィズムに使用できる継承チェーンはありません。
ダックタイピングのようなものを調べる必要があります、またはアダプターパターン、または独自のプロキシクラスを構築して、共通するインタフェース。少数の実装については、null以外のインスタンスを委任する単一のアダプタークラスを構築するだけで済みました。
interface IFeet {
void WashFeet();
}
class FeetAdapter : IFeet {
private PigFeet.Feet _pigFeet;
private HorseFeet.Feet _horseFeet;
private FeetAdapter(PigFeet.Feet pigFeet) {
_pigFeet = pigFeet;
}
private FeetAdapter(HorseFeet.Feet horseFeet) {
_horseFeet = horseFeet;
}
public void WashFeet() {
if (_pigFeet != null) {
_pigFeet.WashFeet();
} else {
_horseFeet.WashFeet();
}
}
public static FeetAdapter Create(AnimalType animalType) {
switch (animalType) {
case AnimalType.Pig:
return new FeetAdapter(new PigFeet.Feet());
case AnimalType.Horse:
return new FeetAdapter(new HorseFeet.Feet());
}
}
}
大規模なケースでは、IFeetを実装するPigFeetAdapterとHorseFeetAdapterを別々に作成し、それらを作成するFeetAdapterFactoryを使用する方がよいでしょうが、概念は上に示したものと同じです。
他のヒント
名前空間のインポートでは、エイリアス特定の名前空間またはメンバーに。
using PigFeet = PigFeet.Feet;
using HorseFeet = HorseFeet.Feet;
//now your sample code should look something like
if( _animalType == AnimalType.Pig )
{
//namespace is pigfeet
PigFeet feet = new PigFeet();
feet.WashFeet();
}
if( _animalType == AnimalType.Horse )
{
//namespace is horsefeet
HorseFeet feet = new HorseFeet();
feet.WashFeet();
}
ネームスペースは、タイプを整理するための単なる方法です。あなたの場合、同じシグネチャを持つメソッドを持っているが、共通のインターフェースを持たない2つ以上の異なるクラスを持っています。クラスのコードを変更できない場合、ここでの重複を避ける唯一の方法は、コンパイル時の型安全性を失いながらリフレクションを使用することです。
改善する前に事態を悪化させている。
すべてのAnimalType決定ロジックを単一のクラスにカプセル化できます。
2つのタイプ(PigsFeetとHorseFeet)の間には、類似の方法がいくつかあります... WashFeetには共通のシグネチャ(パラメーターなしのvoid)があるため、System.Actionを使用してそのメソッドを参照できます。共通の署名(およびパラメーター)を持つ他のメソッドには、System.Func(T)が必要な場合があります。共通の署名のない他のメソッドは、共通の署名に強制する必要がある場合があります。
クライアントコードは次のとおりです。
AnimalFeetFacade myFacade = new AnimalFeetFacade(_animalType);
myFacade.WashFeet();
カプセル化クラスは次のとおりです。
public class AnimalFeetFacade
{
public AnimalFeetFacade(AnimalType theType)
{
if (theType == AnimalType.Pig)
{
_washFeet = WashPigFeet;
//TODO reference more PigFeet methods here
}
else if (theType == AnimalType.Horse)
{
_washFeet = WashHorseFeet;
//TODO reference more HorseFeet methods here
}
else
{
throw new NotImplementedException("AnimalFeetFacade only works with PigFeet and HorseFeet");
}
}
protected Action _washFeet;
public void WashFeet()
{
_washFeet.Invoke();
}
protected void WashPigFeet()
{
PigFeet.Feet = new PigFeet.Feet()
feet.WashFeet()
}
protected void WashHorseFeet()
{
HorseFeet.Feet = new HorseFeet.Feet()
feet.WashFeet()
}
}