chuckd
chuckd

Reputation: 14610

How to avoid large if statements?

I'm sure there is a more OO way of doing this but I'm not sure how. I have different "Report" objects (ex. Report1, Report2, Report3, etc). I have a service object that will take these report objects as two arguments in a method. In the method I have a large if else block statement that determines which two report objects have been passed into the method. This logic doesn't seem that OO, isn't there a better way to determine which two reports I have passed in and then provide the correct logic to those two reports so I don't have a if-else block that spirals out of control and ends up being 100+ lines long? Would the command pattern work well here or is there something better that is more object centric?

Report1 r1 = new Report1();
Report2 r2 = new Report2();
Report3 r3 = new Report3();
Report4 r4 = new Report4();
etc...

SomeServiceObject serviceObj = new SomeServiceObject();
var returnedData1 = serviceObj.GetReportLogic(r1, r2);
var returnedData2 = serviceObj.GetReportLogic(r1, r3);
var returnedData3 = serviceObj.GetReportLogic(r3, r4);
etc..

public GetReportLogic(object someReport1, object someReport2)
{
    if ((someReport1 as Report1) and (someReport2 as Report1))
    {
        DoSomething();
    }
    else if ((someReport1 as Report1) and (someReport2 as Report2))
    {
        DoSomethingElse();
    }
    else if ((someReport1 as Report1) and (someReport2 as Report3))
    {
        DoSomethingElseAgain();
    }
    etc...
}

Upvotes: 4

Views: 2040

Answers (2)

FireAlkazar
FireAlkazar

Reputation: 1880

Check, if Chain of responsibility pattern fits for you (metacode):

public class ChainOfResponsibility
{
    ChainOfResponsibility _next;
    Type _t1;
    Type _t2;
    Action _action;

    public ChainOfResponsibility(Type t1, Type t2, Action action)
    {
        _t1 = t1;
        _t2 = t2;
        _action = action;
    }

    public void Execute(object o1, object o2)
    {
        if(CriteriaMatches(o1, o2))
        {
            _action();
            return;
        }

        if(_next != null)
            _next.Execute(o1,o2);
    }

    public ChainOfResponsibility SetNext(Type t1, Type t2, Action action)
    {
        _next = new ChainOfResponsibility(t1,t2,action);
        return _next;
    }

    private bool CriteriaMatches(object o1, object o2)
    {
        return (o1 as t1) and (o2 as t2);
    }
}

And usage will be:

public GetReportLogic(object someReport1, object someReport2)
{
    var chain = new ChainOfResponsibility(typeof(Report1), typeof(Report1), DoSomething)
                    .SetNext(typeof(Report1), typeof(Report2), DoSomethingElse)
                    .SetNext(typeof(Report1), typeof(Report3), DoSomethingElseAgain);

    chain.Execute(someReport1, someReport2);
}

I wrote the variation of the pattern for the code you provided. Feel free to adapt it to your real needs.

Upvotes: 0

MK.
MK.

Reputation: 34597

OK, my C# is a little rusty, but can't you use method overloading to achieve this? I.e. define multiple methods

public GetReportLogic(Report1 someReport1, Report1 someReport2)
public GetReportLogic(Report1 someReport1, Report2 someReport2)
public GetReportLogic(Report2 someReport1, Report2 someReport2)

...

with different implementations for different arguments?

You could also have a method called, say, combine(Report r) defined in your Report classes and then each Report defines the way it is combined with different other reports.

Upvotes: 8

Related Questions