You can use the Facade pattern like you thought to treat your AppleJuice and OrangeJuice objects like Juice objects. It's pretty simple. Here's your Juice class:
class Juice
{
Juice(AppleJuice aj)
{
this.Color = aj.Color;
this.VitaminC = aj.VitaminC;
}
Juice(OrangeJuice oj)
{
this.Color = oj.Color;
this.VitaminC = oj.VitaminC;
}
public ColorType { get; set; }
public VitaminCType VitaminC { get; set; }
}
This Juice class covers both juice types and extracts the information that you are interested in. To handle Juice equality, you need to implement IEqualityComparer<Juice>:
class JuiceEq : IEqualityComparer<Juice>
{
public bool Equals(Juice x, Juice y)
{
if (x == null) return y == null;
if (y == null) return false;
return x.Color == y.Color && x.VitaminC = y.VitaminC;
}
public int GetHashCode(Juice obj)
{
if(obj == null) return 0;
return new { obj.Color, obj.VitaminC }.GetHashCode();
}
}
Now, to use this when you make you SOAP requests and then remove duplicates:
IEnumerable<Juice> GetJuice()
{
IEnumerable<AppleJuice> appleJuices = SoapAppleJuiceRequestRequest();
IEnumerable<OrangeJuice> orangeJuices = SoapOrangeJuiceRequestRequest();
IEnumerable<Juice> juices = appleJuices.Select(s => new Juice(s))
.Concat(orangeJuices.Select(s => new Juice(s));
IEnumerable<Juice> deDuped = juices.Distinct(new JuiceEq());
return deDuped;
}
The intent of the strategy pattern according to the GoF is to "define a family of algorithms, encapsulate them and make them interchangeable. The strategy lets algorithms vay independently from client that use it"
In your code you apply this pattern, making a strategy of ContentHandler
that can be declined in different concrete content handling, depending on the requests to pursue.
Problem with the switch approach:
However, in your implementation the serialization depends on the format you want to use. The way you pass a content type, using lots of switch
blocks to produce the appropriate format, will make the code very difficult to maintain: each content handler implementation will have to provide for all kind of formats. Imagine that one day you'd like to add a new format (for example bson) : you'd need to review all the switch
blocks of all your concrete implementation of ContentHandler
. That's a huge work, and clearly does not very well enforce separation of concerns.
Alternative:
But looking at it more closely, you have here an opportunity to add a second level of strategies. Each of your switch block would correspond to a kind of primitive operation on the content to produce the format. It's another family of algorithms. You should hence make the format a strategy as well:
public interface SerialFormatter {
String createStringNode(...);
String openSubbloc(...);
... // you have to analyze your switch blocks to determine the primitives
};
And then regroup all format specific primitives according to this logic:
class JSONFormatter implements SerialFormatter { ... };
class XMLFormatter implements SerialFormatter { ... };
If one day you want to support a new format, just add a new class of this kind.
You then can simplify your serializer logic:
String serializeRequest(Content con, SerialFormatter fmt){
// ....
String s = fmt.openSubbloc ("ID") +
fmt.createStringNode ("Name", con.name() ) +
...
fmt.closeSubbloc("ID");
return s;
}
Conclusion
Design using combination of multiple strategies is sometimes called "policy based design" It is a very powerful approach: with n kind of requests and m format, you'd write m+n classes with single responsibility, instead of writing nm classes (see other answer to your question) or writing n classes and at least nm rather redundant cases
.
Best Answer
I am not sure of the pattern name, but a possible scenario is that you will need multiple interfaces to support what has been shown. Each API will choose what interfaces to implement. The manager implements all interfaces and will automatically handle whether or not the current forecaster can perform the desired operation.
So adding more APIs should be straight forward as each API can pick and choose what interfaces to support. All operations are handled in the manager.
Interfaces
APIs
Finally the Manager will implement everything and handle whether or not the current forecaster being managed can perform the operation.
Manager API