Inject a call automatically


Inject a call automatically



I have a scenario which is based on the Open Closed principle. I have a Cart class, which has a method CalculateTotal(). This method takes MODE and QTY as parameters.


Cart


CalculateTotal()


MODE


QTY



Based on the MODE, the amount is calculated.


MODE


public class Cart
{
ICalculator calculator;
public Cart()
{
calculator = new Calculator();
}
public decimal CalculateTotal(string MODE,decimal QTY)
{
return calculator.CalculateTotal(MODE, QTY);
}
}

public interface ICalculator
{
decimal CalculateTotal(string MODE, decimal QTY);
}

public class Calculator : ICalculator
{
private readonly List<IRule> rules;

public Calculator()
{
rules = new List<IRule>();
rules.Add(new OrdinaryRule());
rules.Add(new SpecialRule());
rules.Add(new OfferRule());
}

public decimal CalculateTotal(string MODE, decimal QTY)
{
return rules.First(x => x.IsMatch(MODE)).CalculateTotal(QTY);
}
}

public interface IRule
{
bool IsMatch(string MODE);
decimal CalculateTotal(decimal QTY);
}

public class OrdinaryRule : IRule
{
public decimal CalculateTotal(decimal QTY)
{
return QTY * 2m;
}

public bool IsMatch(string MODE)
{
return MODE.StartsWith("ORD");
}
}



If I need to add a new rule say FestivalRule, then I can implement the interface and create a new rule and add that rule in the Calculator() constructor.


FestivalRule


Calculator()



Still I feel that I'm modifying the Calculator class.


Calculator



Is there any way that I don't have to add/ modify the Calculator class and still the new rule applies?


Calculator





What you need is a. IOC container
– Chetan Ranpariya
Jul 1 at 12:00





Using Strategy Pattern and explicit dependency principle inject the collection of rules. The current design still tightly couples the Calculator to implementation concerns.
– Nkosi
Jul 1 at 12:20





1 Answer
1



The current design still tightly couples your classes to implementation concerns.



Using Strategy Pattern and explicit dependency principle inject the dependencies.


public class Cart {
private readonly ICalculator calculator;

public Cart(ICalculator calculator) {
this.calculator = calculator;
}

public decimal CalculateTotal(string MODE, decimal QTY) {
return calculator.CalculateTotal(MODE, QTY);
}
}

public class Calculator : ICalculator {
private readonly List<IRule> rules;

public Calculator(IEnumerable<IRule> rules) {
this.rules = new List<IRule>(rules);
}

public decimal CalculateTotal(string MODE, decimal QTY) {
return rules.First(x => x.IsMatch(MODE)).CalculateTotal(QTY);
}
}



So now either using pure DI or a container these classes are decoupled from implementation concerns can allow their behavior to be extended without modifying their source code (OCP).


List<IRule> rules = new List<IRule>();
rules.Add(new OrdinaryRule());
rules.Add(new SpecialRule());
rules.Add(new OfferRule());
rules.Add(new FestivalRule()); //<<<

var calculator = new Calculator(rules);

var cart = new Cart(calculator);

//...



A DI container would manage the heavy lifting and the automatic injection of dependencies when resolving an object graph. Provided it has been configured accordingly.






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Boo (programming language)

How to make file upload 'Required' in Contact Form 7?