3

Let me sketch the situation:

  • I have multiple users, with certain properties (2 enums)
  • For each user I need to fetch data, for some with some basic filtering, for some extended filtering (= basic filtering + extra filtering). I'd like to do that not separate for every user, but I'd rather group the users and do it in two queries.
  • For every user, I need to filter that data depending on the values of the enums. I will always need to do GetFirstData() (method depending on first enum), GetLastData() (method depending on second enum), CheckData() (depending on both enums).

I've been looking at the Strategy Pattern, but it seems that's more designed to implement one behavior. I want to combine my behaviors to avoid making the combinations between all GetFirstData and GetLastData, is there any pattern to do this better? I've been thinking on just using 2 delegates and assign the corresponding methods depending on the values of the enums. Would this be the cleanest way?

Little example of what I mean:

public class User
{
   public Enum1 FirstEnum {get; set;}
   public Enum2 SecondEnum {get; set;}
   ...
}
public IEnumerable<Data> Filter(int userId, Expression extraFilter)
{
    var data = GetData(userId);
    if(extraFilter != null)
      data = data.Where(extraFilter);
    return data;
}
public Data GetFirstData(IEnumerable<Data> data);
public Data GetLastData(IEnumerable<Data> data);
public bool CheckData(IEnumerable<Data> data);

My endresult could do something like this:

public class EndResult
{
    public Data FirstResult {get; set;}
    public Data SecondResult {get; set;}
    public Func<IEnumerable<Data>,Data> GetFirstData {get; set;}
    public Func<IEnumerable<Data>,Data> GetLastData {get; set;}
    public bool ExtendeFiltering {get; set;}

    public EndResult(User user)
    {
        switch(user.enum1)
        {
            case: GetFirstData = specificFunction;
                  ExtendedFiltering = true;
            ...
        }
        //Second for GetLastData;
    }

    public void Execute()
    {
        GetData();
        CheckData();
        GetFirstData();
        GetLastData();
    }
}

Edit: For future readers who are curious, I didn't use delegates (not directly at least). I created 2 interface IFirst and ILast with a corresponding method. In my static create method defined on my processor class, I do the logic to create an instance of those interfaces based on certain conditions. The reason I left the path of directly using delegates is because it turned out I needed more parameters than just User for some of them. So I resorted to different implementations based on the parameters I need in the constructor of those classes.

  • 2
    I don't really see how your suggested use of delegates is any different to the strategy pattern. Could you elaborate on this? – Jules Mar 1 '16 at 9:54
  • I just don't know if this is a clean approach, I would be passing delegates to the constructor, instead of creating a different instance for each different kind of processing the data. So depending on 2 switches I would choose the corresponding delegates. True strategy pattern seems cleaner by just creating an instance depending on a value. – Alexander Derck Mar 1 '16 at 9:57
  • Strategy pattern usually passes the strategy object to the constructor also, in order to allow the behaviour of the object to configure what strategy to use. I presume you're suggesting creating a strategy for each user? – Jules Mar 1 '16 at 10:09
  • @Jules Yes, now I would have 1 class with a few delegates that need to be assigned. Would it be better to create an implementation (1 class) per behavior? The problem is that I have combinations of them. – Alexander Derck Mar 1 '16 at 10:11
  • 1
    Are you familiar with the Table Data Gateway pattern? I think this might be a better fit to your problem than the row-based approach you're currently using. – Jules Mar 1 '16 at 10:15
6

Using delegates in the suggested manner is a specific form of the strategy pattern which can always be used if the strategy objects are as simple as a function (see here, for example).

However, the essence of your code is that you have an object of type EndResult which encapsulates how a set of operations interact (if the operations are given by strategy objects or "strategy delegates" does not matter). This is called Mediator pattern, the Mediator here provides what is called "context" in this description of the strategy pattern.

Deciding between the different strategies will typically be the task of a factory method. If you make that method part of your mediator (as in your example, in the constructor of the EndResult), or if you prefer to delegate this to another class, is something you need to decide by yourself. It depends on things of the overall size and structure of that class and the surroundings, and how much "separation of concerns" you really need. I would typically start with a "small solution" (both in one class) and refactor as soon as the class starts getting "too large".

  • Thanks, so if I understand correctly I'd put all my methods in one place and let the 'mediator' decide the appropriate methods for my users? – Alexander Derck Mar 1 '16 at 12:26
  • @AlexanderDerck: see my edit – Doc Brown Mar 1 '16 at 13:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.