Saturday, January 8, 2011

Dependency Injection C# vs Python

Just to make sure I understand the dependency injection concept, I wrote a little simple showing 2 highly coupled classes and the loosely coupled solution in C# and in Python.

Highly Coupled Dependency in C#

Because the classes Invoice and SaleTaxe are Highly Coupled and the class SaleTaxe use the DB class to read the sale taxe from the database, it is impossible to unit test the Invoice class without an SaleTaxe instance and a database.

public class SaleTaxe {

        private Decimal _Value = 0;

        public SaleTaxe() {

            _Value = DB.Read("SaleTaxe");
        }
        
        public Decimal Value {
            get { 
                return this._Value;
            }
        }
    }

    public class Invoice {

        private SaleTaxe  _SaleTaxes          = null;
        private Decimal   _AmountBeforeTaxe   = 0;

        public Invoice(decimal amountBeforeTaxe) { 

            _SaleTaxes        = new SaleTaxe();   // << HighlyCoupledDependency
            _AmountBeforeTaxe = amountBeforeTaxe;
        }

        public Decimal TotalAmount {
            get { 
                return this._AmountBeforeTaxe + (this._AmountBeforeTaxe * this._SaleTaxes.Value / 100);
            }
        }
    }

Loosely Coupled Dependency in C# To implement a loose coupling we are using an interface.
public interface ISaleTaxes {

        decimal Value { get; }
    }

    public class SaleTaxes : ISaleTaxes {

        private Decimal _Value = 0;

        public SaleTaxes() {

            _Value = DB.Read("SaleTaxe");
        }

        public Decimal Value {
            get { 
                return this._Value;
            }
        }
    }

    public class Invoice {

        private ISaleTaxes  _SaleTaxes          = null;
        private Decimal     _AmountBeforeTaxe   = 0;

        public Invoice(decimal amountBeforeTaxe, ISaleTaxes saleTaxes) { 

            _SaleTaxes          = saleTaxes;
            _AmountBeforeTaxe   = amountBeforeTaxe; // << LooseCoupling
        }

        public Decimal TotalAmount {
            get { 

                return this._AmountBeforeTaxe + (this._AmountBeforeTaxe * this._SaleTaxes.Value / 100);
            }
        }
    }


Unit Testing Now we can create a class SaleTaxesForTesting just for unit testing.
class SaleTaxesForTesting : DependencyInjection.LooseCoupling.ISaleTaxes {

            public Decimal Value {
                get {
                    return 10;
                }
            }        
        }

        [TestMethod]
        public void LooseCouplingDependency_TotalAmount() {
            
            DependencyInjection.LooseCoupling.Invoice i = new DependencyInjection.LooseCoupling.Invoice(1, new SaleTaxesForTesting());
            Assert.AreEqual(1.10M, i.TotalAmount);            
        }


And now in Python In Python there is no need to create the interface. Any instance referencing another is loosely coupled. See Uncle Bob's SOLID principal.
class SaleTaxes:

    def __init__(self):

        self.Value = DB.Read("SaleTaxe")

class Invoice:

    def __init__(self, amountBeforeTaxe, saleTaxes):

        self.AmountBeforeTaxe   = amountBeforeTaxe
        self.SaleTaxes          = saleTaxes

    def TotalAmount(self):

        return self.AmountBeforeTaxe + (self.AmountBeforeTaxe * self.SaleTaxes.Value / 100.0)

# Unit Tests

class SaleTaxesForTesting:

    def __init__(self):

        self.Value = 10

class UnitTests(unittest.TestCase):

    def test_LooseCouplingDependency_TotalAmount(self):

        i = Invoice(1, SaleTaxesForTesting())
        self.assertEqual(1.10, i.TotalAmount())

No comments:

Post a Comment