Strategy Pattern with Different parameters in interface (C#)
Asked Answered
N

6

10

I am basically trying to implement a Strategy pattern, but I want to pass different parameters to the "interfaces" implementation (that inherit from the same object) and don't know if this is possible. Maybe I'm choosing the wrong pattern, I get an error similar to

'StrategyA' does not implement inherited abstract member 'void DoSomething(BaseObject)'

with the code below:

abstract class Strategy
{
 public abstract void DoSomething(BaseObject object);
}

class StrategyA : Strategy
{
 public override void DoSomething(ObjectA objectA)
 {
  // . . .
 }
}

class StrategyB : Strategy
{
 public override void DoSomething(ObjectB objectB)
 {
  // . . .
 }
}

abstract class BaseObject
{
}

class ObjectA : BaseObject
{
 // add to BaseObject
}

class ObjectB : BaseObject
{
 // add to BaseObject
}

class Context
{
   private Strategy _strategy;

 // Constructor
 public Context(Strategy strategy)
 {
  this._strategy = strategy;
 }

    // i may lose addtions to BaseObject doing this "downcasting" anyways?
 public void ContextInterface(BaseObject obj) 
 {
  _strategy.DoSomething(obj);
 }

}
Nude answered 24/12, 2009 at 17:29 Comment(2)
+1 such a common scenario, i've seen implementations where obj keeps growing and growing...Claque
Use Interfaces instead of Classes eg public interface { void DoSomething(BaseObject object); } Then have Strategy inherit that interface. Base your SP around the Interface or a IStrategy inteface that inherits from this interface. BTW use DIP for Injection with a IoC like NinjectPentateuch
K
16

It sounds like you're actually trying to reinvent the Visitor pattern, instead of just using the Strategy pattern the way it was intended.

Also, since you're using C#, I'd recommend reading Judith Bishop's paper titled On the Efficiency of Design Patterns Implemented in C# 3.0. This covers multiple approaches to the visitor pattern in detail, and has some interesting, related useful ideas.

Kern answered 24/12, 2009 at 17:33 Comment(5)
i am converting 2 different file formats to a different format, if that helps - i'm converting formats A and B both to CNude
One interface, with a ObjectC ConvertToC() method, is probably all you need, in that case. Format A and Format B (or a class that works with those formats) just needs to implement that interface, and you're done.Kern
but if wanted 2 methods - ObjectC ConvertToC(ObjectA a), ObjectC ConvertToC(ObjectB b), I think I would still have the same problemNude
You could make your interface: ConvertToC(). Then just construct your converters with the approrpiate objects themselves (ie: AConverter convert = new AConverter(a); ObjectC result = convert.ConvertToC();Kern
If you really want to support multiple ConvertToC(multipleClassesHere obj) , then you probably want the visitor pattern, or a variant as proposed in that paper.Kern
I
8

In C# method signature includes its name, type parameter list and formal parameter list. In the code above "overrides" have different signatures than virtual method and thus it is not allowed.

The core idea behind Strategy Pattern is to define set of interchangeable algorithms with details hidden inside. But if your strategies differ (by type) in what they can accept as input they are no longer interchangeable. So it seems this a wrong pattern to use in this situation.

Intrust answered 24/12, 2009 at 17:44 Comment(0)
A
5

You might want to consider this article: http://hillside.net/plop/2010/papers/sobajic.pdf The pattern is called "parameterized strategy pattern" and should match what you need. Basically, it builds up on the strategy pattern and allows for strategies (different algorithms) to have different parameters. Parameters are encapsulated in special classes, i.e. parameter classes. Each strategy (i.e. algorithm) needs to implement GetParameters() method which sends back the list of parmaters instances for specific algorithm.

Aboulia answered 20/9, 2011 at 20:10 Comment(0)
E
2

The strategy pattern is meant to provide different behaviour on input objects of the same type.

What you're actually trying to do is context-dependent, and I'm not sure it can be seen from the code that was posted.

Ey answered 24/12, 2009 at 17:40 Comment(0)
L
0

You could create a Parameters class like so:

public class Parameters
{
  public ObjectA {get; set;}
  public ObjectB {get; set;}
}

The alter your methods to accept Parameters such as:

class StrategyA : Strategy
{
 public override void DoSomething(Parameters parameters)
 {
      //  Now use ObjectA
      if(parameters.ObjectA.SomeProperty == true)
      { ... }
 }
}

This way you can additional parameters should your requirements change in the future. Another alternative is to use Dictionary<string, object> where you can do:

class StrategyA : Strategy
{
     public override void DoSomething(Dictionary<string, object>parameters)
     {
          //  Now use ObjectA
          var someProperty = (bool)parameters["SomeProperty"];
          if() ...
     }
}
Landgrabber answered 31/7, 2010 at 1:31 Comment(0)
R
0

It does sound like a design issue to me. The strategy pattern is about treating homogeneous inputs with different behaviors, not about switching behaviors based on the type of inputs.

This is outside of the scope of what the strategy pattern can do. If you can figure out how to make those inputs homogeneous, then you're good to go. Otherwise, don't try using this pattern.

An ugly alternative is to pass a "data bag" to the strategies instead of having a properly defined interface for them.

This kinda sounds like the visitor pattern to me but I'm not completely sure.

Respectability answered 24/8 at 17:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.