Strategy Pattern the right thing?
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
}
}
clas开发者_Python百科s 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
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();
}
}
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.
In similar circumstances I choose between reflection and if/case
s 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.
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
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.
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 -
- Reading the implementation class and assembly name from the configuration file and creating it using reflection.
- Creating a dictionary of proxy instances with soap version as keys.
精彩评论