策略模式是对的吗?

时间:2010-11-30 10:54:02

标签: oop design-patterns strategy-pattern

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

我有一个班级做肥皂调用。但是如果肥皂定义发生变化,我将不得不写一个新的类或继承它。 所以我开始写解决方案来写这样的东西:

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-Function应该是静态的

6 个答案:

答案 0 :(得分: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();
 }

}

答案 1 :(得分:1)

如果您只在工厂或代码中使用了switch-cases,则会有所不同。您可以在一个点上做出决定(选择哪种实施方案)。

答案 2 :(得分:1)

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

答案 3 :(得分:1)

您不需要切换或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的示例以获取策略以查看我的意思,如果不清楚

答案 4 :(得分:0)

因为version仅在运行时已知,所以它肯定会归结为某些条件(如果或切换或使用字符串和原型之间的映射等)。

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

答案 5 :(得分:0)

你应该program to an interface not an implementation

有一个单独的服务界面,您可以从客户端使用。

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

并将您的客户编码为 -

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

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

然后您可以开始使用条件逻辑来创建适当的代理到ServiceFactory类。稍后您可以使用以下技术更改它以删除条件逻辑,例如 -

  1. 从配置文件中读取实现类和程序集名称,并使用反射创建它。
  2. 使用soap版本作为密钥创建代理实例的字典。