Oop 战略模式是正确的吗?
我希望你能帮助我解决我的问题: 我有一个班在做soap调用。但是如果soap定义发生变化,我将不得不编写一个新类或从中继承。 所以我找到了解决方案,写了这样的东西: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 {
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