How to obey the Open / Closed principle in this situation?

2

I have a situation where the solution I identified clearly violates the Open / Closed principle and I would like to find a better solution that does not violate this principle. Obviously my concern is not simply to "obey the principle" but rather to build a code that is easier to maintain later.

The scenario is basically the following: we have a program coded in Windows Forms and we need to implement the execution of periodic tasks. The meaning of this is basically the following: we want to produce the ability that according to a criterion of each task, the system on a given day presents a window to the user asking if he wants to do it or not, the ability to delay the next time you open the system.

The solution I found, including the simplest one was: create a EPeriodicTasks enumeration that contains a list of the tasks that the system implements. I also thought about creating a EPeriodicTaskStatus enumeration with Completed , Delayed and Canceled values. After that, then create a class: PeriodicTaskLog that records the execution information. It simply has PeriodicTask properties of type EPeriodicTasks , DateExecution type DateTime , ExecutionStatus type EPeriodicTaskStatus .

Finally, I implement a PeriodicTaskService service that contains a method: RunPeriodicTasks that runs every time the program starts.

This class then has two methods for each PeriodicTask : a verification method, which implements the criterion to see if that day needs to perform this task. Among other things, this method checks to see if it was already done on that day by querying the PeriodicTaskLogs . The second method is the execution itself, which can simply open another window of the program, or simply do something in the background.

The problem with this solution is that it clearly violates the Open / Closed principle, joins a lot of responsibility in the PeriodicTaskService class, and makes maintenance difficult. To add a PeriodicTask you need to go there and change that class, and if many are created as the program evolves according to requirements, this class will get intractable.

This all has an obvious and very good solution: every periodic task has its own class, encapsulating the verification logic if it should run, and along with checking the logic itself.

The problem is this: each periodic task needs to be related to a single enumeration value, to be able in the log to identify which is which. I can associate an enumeration value to an object, but not to a u class, since the class is only the object model, not having its own values. I could even implement a static member for this, but it seems gambiarra.

How can I improve my solution to comply with the Open / Closed principle and also the Single Responsability Principle? How can I resolve this deadlock and improve this modeling?

    
asked by anonymous 31.03.2017 / 18:19

1 answer

1

Good afternoon Leonardo, I recommend you solve your problem using Rules Pattern.

With this, you will have a unique responsibility for each type of task you will do and will also respect Open / Closed.

You have an example of how to use Rules Pattern:

public class RulesDiscountCalculator: IDiscountCalculator {     List _rules = new List ();

public RulesDiscountCalculator()
{
    _rules.Add(new BirthdayDiscountRule());
    _rules.Add(new SeniorDiscountRule());
    _rules.Add(new VeteranDiscountRule());
    _rules.Add(new LoyalCustomerRule(1, 0.10m));
    _rules.Add(new LoyalCustomerRule(5, 0.12m));
    _rules.Add(new LoyalCustomerRule(10, 0.20m));
    _rules.Add(new NewCustomerRule());
}

public decimal CalculateDiscountPercentage(Customer customer)
{
    decimal discount = 0;

    foreach (var rule in _rules)
    {
        discount = Math.Max(rule.CalculateCustomerDiscount(customer), discount);
    }

    return discount;
}

}

For an explanation of the example see:

link

Abc!

    
31.03.2017 / 19:07