策略模式正确吗?

发布于 2024-10-05 22:05:29 字数 849 浏览 5 评论 0原文

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

我有一堂课正在做肥皂通话。但是如果肥皂定义发生变化,我将不得不编写一个新类或继承它等。 所以我找到了写这样的解决方案:

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。使用面向对象技术可以实现这一点吗?

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

i hope you can help me with my problem:

I have a Class doing soap calls. But if the soap definition changes i'll have to write a new class or inherit from it etc.
So I came to the solution to write something like that:

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

Well pretty bad code, i know. Then I read about the Strategy pattern and i thought, wow that's what i need to get rid of this bad switch-case thing:

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}

But i can't avoid using "ifs" or switch cases in my code. Is this possible using OO-techniques??

Edit:
The GetSoapVersion-Function should be static

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

夜还是长夜 2024-10-12 22:05:29

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

}

That's more or less the right way to do this in a beautiful fashion.
At some point in your code, you'll have to make a decision whether v1 or v2 has to be used, so you'll have to have a conditional statement (if or switch) anyway. However, when using a strategy and a factory (factory method or factory class), you've centralized that decision.

I would make my factory method on the abstract class static though.
Also, I would make use of the template-method pattern: that is, a public, non overridable GetData method which calls a protected virtual (abstract) method that should be overriden in a concrete implementation.

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();
 }

}

半寸时光 2024-10-12 22:05:29

如果您的 switch-case 只在工厂中使用,或者在代码中到处都有,那就有区别了。您可以在一个点上做出决定(选择什么实现)。

It is a difference if you have your switch-cases only in factories, or all over your code. You have your decision (what implementation to choose) on a single point.

可是我不能没有你 2024-10-12 22:05:29

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

In similar circumstances I choose between reflection and if/cases using the following criterion: if new version support should be added dynamically (like plug-ins) I choose reflection, otherwise - if/case. As mentioned in other answers that it should inside a factory method to provide a single place to create things. It worths to mention that Strategy is a behavioral pattern, while what you asked for looks like to be creational.

阳光下的泡沫是彩色的 2024-10-12 22:05:29

您不需要 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 的策略示例以了解我的意思

You do not need switch or if statements.
Just use delegation.
I.e. the concrete implementations of the abstract class will perform as needed (i.e. SoapV1, SoapV2 etc) and the client sets the appropriate instance in the object reference.
You have only a reference to the base class and the appropriate subclass is set by the client. Your code just calls the methods of the base class (which in runtime is one of the derived implementations). E.g. an example (DISCLAIMER:Have not compiled code. Only a sample)

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

Check the example of GoF for strategy to see what I mean, if it is not clear

小姐丶请自重 2024-10-12 22:05:29

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

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

Because version is only known at runtime it will definitely boil down to some conditional (if or switch or using a map between strings and a prototype etc).

Hence the worthy goal is to reduce the number of conditionals/isolate the change points.

少女七分熟 2024-10-12 22:05:29

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

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

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

并将您的客户端编码为 -

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

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

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

  1. 从配置文件中读取实现类和程序集名称并使用反射创建它。
  2. 创建一个代理实例字典,以肥皂版本为键。

You should program to an interface not an implementation.

Have a separate service interface which you can use from your client side.

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

and code your client as -

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

This way your client code will not change when the service proxy changes.

Then you to start with you can move the conditional logic for creating the appropriate proxy to the ServiceFactory class. Later on you can change it to remove conditional logic using following techniques like -

  1. Reading the implementation class and assembly name from the configuration file and creating it using reflection.
  2. Creating a dictionary of proxy instances with soap version as keys.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文