3

我希望你能帮我解决我的问题:

我有一个班级做肥皂电话。但是,如果肥皂定义发生变化,我将不得不编写一个新类或从它继承等。所以我找到了解决方案来编写类似的东西:

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

好吧,代码很糟糕,我知道。然后我读到了策略模式,我想,哇,这就是我需要摆脱这个糟糕的 switch-case 的东西:

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”或 switch case。这可能使用 OO 技术吗?

编辑:GetSoapVersion-Function 应该是静态的

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

如果您的 switch-case 仅在工厂中或在您的代码中使用,那就不同了。你有你的决定(选择什么实现)在一个点上。

于 2010-11-30T11:02:56.737 回答
1

在类似的情况下,我if/case使用以下标准在反射和 s 之间进行选择:如果应该动态添加新版本支持(如插件),我选择反射,否则 - if/case。正如其他答案中提到的那样,它应该在工厂方法中提供一个创建事物的地方。值得一提的是,这Strategy是一种行为模式,而您所要求的似乎是创造性的。

于 2010-11-30T11:10:45.453 回答
1

您不需要 switch 或 if 语句。
只需使用代表团
即抽象类的具体实现将根据需要执行(即 SoapV1、SoapV2 等),并且客户端在对象引用中设置适当的实例
您只有对基类的引用,并且适当的子类由客户端设置。您的代码只调用基类的方法(在运行时是派生实现之一)。例如一个例子(免责声明:没有编译代码。只有一个例子)

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只在运行时才知道它肯定会归结为一些条件(如果或切换或使用字符串和原型之间的映射等)。

因此,有价值的目标是减少条件的数量/隔离变化点。

于 2010-11-30T11:02:52.467 回答
0

您应该对接口而不是实现进行编程

有一个单独的服务接口,您可以从客户端使用它。

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

并将您的客户编码为 -

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

这样,当服务代理更改时,您的客户端代码不会更改。

然后,您首先可以将用于创建适当代理的条件逻辑移动到ServiceFactory类。稍后您可以使用以下技术更改它以删除条件逻辑 -

  1. 从配置文件中读取实现类和程序集名称并使用反射创建它。
  2. 创建一个以soap版本为键的代理实例字典。
于 2010-11-30T11:09:28.307 回答