C # Build application partiii using design patterns and Software Design Principles

Source: Internet
Author: User

Dependency Injection

What are the main points of this principle. Why can't you hard-code the instance of the class again? When coding and testing, let's focus on a very important thing. Hope you know the unit test and its importance. Maybe you should design your test first before you perform any encoding, so you should be familiar with test-driven development. To define new features, you should write tests. You should try to implement and start coding until the test passes. Let's take a look at the code of the previous article.

public class DateBasedTaxFactory:ITaxFactory    {        Customer _customer;        ITaxFactory _taxFactory;        public DateBasedTaxFactory(Customer c, ITaxFactory cb)        {            _customer = c;            _taxFactory = cb;        }        public ITax GetTaxObject()        {            if (_customer.StateCode == "TX"                && DateTime.Now.Month == 4                && DateTime.Now.Day == 4)                return new NoTax();            else                return _taxFactory.GetTaxObject();        }    }

We have datebasedtaxfactory, when we should test whether this factory can work normally. Whether the return value of this tax type is 0 in April 4 every year. We may create the following test.

Customer cust = new Customer(){StateCode = "TX", County = "Travis", ZipCode = "78745"};    DateBasedTaxFactory db = new DateBasedTaxFactory(cust, new CustomerBasedTaxFactory(cust));    ITax tax = db.GetTaxObject();    //test for no tax for a certain date    if(tax.CalculateTax(3m) != 0)    {        throw new Exception("the value is supposed to be zero");    }

Is there any problem? We cannot really test this! As you can see in datebasedtaxfactory, to test the current date, it uses the now attribute of the datetime object directly. Unless you change the system time, we cannot meet notax conditions. It is not ideal to change the system time. Can we do other things? Sometimes this factory class has a reference to a hidden attribute, which is implemented by hard coding and depends on something that needs to be changed. The factory class requires a datetime object. It does not need datetime to be the current date. It does not focus on the date given to it. To tell the outside world what this class needs to do, we need to use dependency injection. This will allow our test to give him any date to be tested. As shown below:

public class DateBasedTaxFactory : ITaxFactory{    Customer _customer;    ITaxFactory _taxFactory;    DateTime _dt;    public DateBasedTaxFactory(Customer c, ITaxFactory cb,DateTime dt)    {        _customer = c;        _taxFactory = cb;        _dt = dt;    }    public ITax GetTaxObject()    {        if (_customer.StateCode == "TX" && _dt.Month == 4 && _dt.Day == 4)        {            return new NoTax();        }        else            return _taxFactory.GetTaxObject();    }} 

Now we can adjust our test to send any date we want to test.

Customer cust = new Customer(){StateCode = "TX",County ="Travis",ZipCode = "78745"};DateBasedTaxFactory db = new DateBasedTaxFactory(cust, new CustomerBasedTaxFactory(cust),    new DateTime(2001,4,4));ITax tax = GetTaxObject();//test for no tax for a certain dateif (tax.CalculateTax(3m) != 0){    throw new Exception("the value is supposed to be zero");}

Single principle/open and closed Principle

Why should you only do one thing for your object? Why should you never change them? Why is the code that shows that life has changed? Let's take a look at the Order class of the first stable version. Okay, if your company has a strong policy, there is only one release version of the main assembly businesslogic. dll in your system every two months. If there is a bug or changes need to be made before that, this will be a tedious and arduous task. However, we can use less effort to define a complementary release assembly. If the following source code is used:

public class Order{    List<OrderItem> _orderItems = new List<OrderItem>();    public decimal CalculateTotal(Customer customer)    {        decimal total = _orderItems.Sum((item)=>{            return item.Cost * item.Quantity;        });        decimal tax;        if (customer.StateCode == "TX")            tax = total * .08m;        else if (customer.StateCode == "FL")            tax = total * .09m;        else            tax = .03m;        total = total + tax;        return total;    }}

If the tax logic in tx changes or a new state tax is required, we must modify the order object. This will cause a bad smell because we need to test and release businesslogic. DLL. because it is related to taxes and taxes, if things change a lot and he is about to invest in the production ASAP, law and money are a good choice.

From other articles, we have done what we need to do, for example:

 public interface ITax    {        decimal CalculateTax(decimal total);    }    public class TXTax:ITax    {        public decimal CalculateTax(decimal total)        {            return total * 0.08m;        }    }    public class CustomerBasedTaxFactory:ITaxFactory    {        Customer _customer;        static Dictionary<string, ITax> stateTaxObjects = new Dictionary<string, ITax>();        static Dictionary<string, ITax> countyTaxObjects = new Dictionary<string, ITax>();        public CustomerBasedTaxFactory(Customer customer)        {            _customer = customer;        }        public ITax GetTaxObject()        {            ITax tax;            if(!string.IsNullOrEmpty(_customer.County))            {                if (!countyTaxObjects.Keys.Contains(_customer.StateCode))                {                    tax = (ITax)Activator.CreateInstance("Tax", "Solid.taxes." + _customer.County + "CountyTax");                    countyTaxObjects.Add(_customer.StateCode, tax);                }                else                    tax = countyTaxObjects[_customer.StateCode];            }            else            {                if (!stateTaxObjects.Keys.Contains(_customer.StateCode))                {                    tax = (ITax)Activator.CreateInstance("Tax", "Solid.taxes." + _customer.StateCode + "Tax");                    stateTaxObjects.Add(_customer.StateCode, tax);                }                else                    tax = stateTaxObjects[_customer.StateCode];            }            return tax;        }    }

We have our taxfactory to create the tax object and all the tax logic is completed in its separate class. So far, the itax class can be introduced into other assembly for tax-related tasks. Tax. dll. If there is a change, you only need to test it in the current Assembly, and its additional assembly will not have too many things.

Okay, that's it. See you next time.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.