3

私はあなたが私の問題で私を助けることができることを願っています:

私は石鹸の呼び出しをしているクラスを持っています。しかし、soapの定義が変更された場合は、新しいクラスを作成するか、そこから継承する必要があります。そこで、次のようなものを作成するソリューションにたどり着きました。

switch(version)
{
  case "1.0":
     saopV1.getData()
  case "2.0":
     soapV2.getData()
}

かなり悪いコードだと思います。それから私はストラテジーパターンについて読みました、そして私はそれが私がこの悪いスイッチケースのものを取り除くために必要なものだと思いました:

abstract SoapVersion
{
    public SoapVersion GetSoapVersion(string version)
    {
         //Damn switch-case thing
         //with return new SoapV1() and return new SoapV2()
    }
    public string[] virtual getData()
    {
          //Basic Implementation
    }
}

class SoapV1:SoapVersion
{
       public override string[] getData()
       {
           //Detail Implementation
       }
}

class SoapV2:SoapVersion
{//the same like soapv1}

しかし、コードで「ifs」を使用したり、大文字と小文字を切り替えたりすることは避けられません。これはOO技術を使用して可能ですか?

編集:GetSoapVersion-関数は静的である必要があります

4

6 に答える 6

4

これは、これを美しい方法で行うための多かれ少なかれ正しい方法です。コードのある時点で、v1とv2のどちらを使用するかを決定する必要があるため、とにかく条件ステートメント(ifまたはswitch)を用意する必要があります。ただし、ストラテジーとファクトリ(ファクトリメソッドまたはファクトリクラス)を使用する場合は、その決定を一元化します。

ただし、抽象クラスのファクトリメソッドを静的にします。また、テンプレートメソッドパターンを使用します。つまり、具体的な実装でオーバーライドする必要がある保護された仮想(抽象)メソッドを呼び出す、オーバーライドできないパブリックGetDataメソッドです。

public abstract class SoapProcessor
{

    protected SoapProcessor() { /* protected constructor since public is of no use */  }

    public static SoapProcessor Create( SoapVersion version )
    {
          switch( version )
          {
               case SoapVersion.Version1 : return new SoapV1Processor();
               case SoapVersion.Version2 : return new SoapV2Processor();
               default: throw new NOtSupportedException();
          }
    }


    public string[] GetData()
    {
         return GetDataCore();
    }

    protected abstract GetDataCore();
 }

}

于 2010-11-30T11:01:22.027 に答える
1

スイッチケースが工場だけにあるのか、コード全体にあるのかは違います。単一のポイントで決定(どの実装を選択するか)があります。

于 2010-11-30T11:02:56.737 に答える
1

if/case同様の状況で、次の基準を使用してリフレクションと s のどちらかを選択します。新しいバージョンのサポートを (プラグインのように) 動的に追加する必要がある場合はリフレクションを選択し、それ以外の場合は - を選択しますif/case。他の回答で述べたように、ファクトリ メソッド内で単一の作成場所を提供する必要があります。それStrategyは行動パターンであることに言及する価値がありますが、あなたが求めたものは創造的であるように見えます.

于 2010-11-30T11:10:45.453 に答える
1

switch または if ステートメントは必要ありません。委任
を使用するだけです。 つまり、抽象クラスの具体的な実装 (SoapV1、SoapV2 など) は必要に応じて実行され、クライアントはオブジェクト参照で適切なインスタンスを設定します。 基本クラスへの参照のみがあり、適切なサブクラスはクライアントによって設定されます。あなたのコードは、基本クラスのメソッドを呼び出すだけです (これは、実行時に派生実装の 1 つです)。たとえば、例(免責事項:コードをコンパイルしていません。サンプルのみ)

public abstract class SoapHandler
{

    protected abstract string[] getData();
 }

public class SoapHandlerV1 extends SoapHandler
{

    public string[] getData(){
        //V1 implementation
    }

}
public class SoapHandlerV2 extends SoapHandler
{

    public string[] getData(){
        //V2 implementation
    }

}


public class SoapProcessor{

    public SoapHandler soapHandler;

    public setSoapHandler(SoapHandler h)
    {
                soapHandler = h;
    }

    public String[] getData(){
        //delegate to specific version
        soapHandler->getData();
    }
}


//in your code
SoapProcessor soap = new SoapProcessor();
soap.setSoapHandler(new SoapHandlerV1());
String[] soapData = soap.getData();//Will get the appropriate version
//use soap data
//do stuff

明確でない場合は、戦略の GoF の例を確認して、意味を確認してください。

于 2010-11-30T11:13:20.780 に答える
0

実行時にのみ知られているのでversion、それは確かに何らかの条件付きに要約されます(ifまたはswitch、または文字列とプロトタイプ間のマップの使用など)。

したがって、価値のある目標は、条件の数を減らす/変更点を分離することです。

于 2010-11-30T11:02:52.467 に答える
0

実装ではなく、インターフェースにプログラムする必要があります。

クライアント側から使用できる別のサービスインターフェイスを用意します。

public interface IService
{
    string[] GetData();
}

クライアントを-としてコーディングします

IService srvice = ServiceFactory.GetProxy();
string[] value = service.GetData();

このようにして、サービスプロキシが変更されてもクライアントコードは変更されません。

ServiceFactory次に、適切なプロキシを作成するための条件付きロジックをクラスに移動することから始めます。後で、次のような手法を使用して条件付きロジックを削除するように変更できます。

  1. 構成ファイルから実装クラスとアセンブリ名を読み取り、リフレクションを使用して作成します。
  2. 石鹸のバージョンをキーとして使用してプロキシインスタンスの辞書を作成します。
于 2010-11-30T11:09:28.307 に答える