Oop 战略模式是正确的吗?

Oop 战略模式是正确的吗?,oop,design-patterns,strategy-pattern,Oop,Design Patterns,Strategy Pattern,我希望你能帮助我解决我的问题: 我有一个班在做soap调用。但是如果soap定义发生变化,我将不得不编写一个新类或从中继承。 所以我找到了解决方案,写了这样的东西: switch(version) { case "1.0": saopV1.getData() case "2.0": soapV2.getData() } 我知道,代码很糟糕。然后我读了关于战略模式的书,我想,哇,这就是我需要摆脱这个糟糕的开关案例的原因: abstract SoapVersion {

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

我有一个班在做soap调用。但是如果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函数应该是静态的

,这或多或少是以漂亮的方式实现这一点的正确方法。 在代码中的某个时刻,您必须决定是否必须使用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();
 }

}因为
版本只有在运行时才知道,所以它肯定会归结为一些条件(如果或切换,或使用字符串和原型之间的映射等)


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

如果您的切换案例仅在工厂中使用,或者在整个代码中使用,则会有所不同。您可以在单个点上做出决定(选择什么实现)。

您应该这样做

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

public interface IService
{
    string[] GetData();
}
并将您的客户编码为-

IService srvice = ServiceFactory.GetProxy();
string[] value = service.GetData();
这样,当服务代理更改时,客户端代码不会更改

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

  • 从配置文件中读取实现类和程序集名称,并使用反射创建它
  • 创建以soap版本为键的代理实例字典

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

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


    查看GoF的示例了解我的意思,如果不清楚,请告诉我为什么在这种情况下接口比抽象类更好。抽象类包含(静态)工厂方法(使用接口不可能),抽象类可以包含基本(或公共)实现(如果适用,在这种情况下不清楚)。使用asbract类时,客户端代码也不会更改。。我想强调的一点是,调用服务方法的代码不应该包含任何条件逻辑。如果抽象类比接口更合适的话,使用抽象类也可以。谢谢你的回答。我实际上不知道模板方法模式,它在以后非常有用。但在这种情况下,我需要定义一个默认实现。所以这个模式不是必需的,是吗?当你需要定义一个默认的实现时,我认为你不应该也需要一个抽象类。关于插件的有用信息,谢谢。所以我实现了工厂方法模式而不是策略模式??我现在有点困惑。还是工厂法是一种战略模式?@fczler 1。我会用工厂的方法。2.不,工厂方法不是一种策略。这一讨论可能有益于:
    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