Sunday, March 25, 2012

Design Patterns: Interface

       The most important concept of OOP is probably interface. I personally think it's the beginning of all OOP magic. The terminology "interface" is independent of certain programming language, although most modern programming languages have a "interface" keyword. A interface is a contract between consumer object and supplier object. For example, you hire a painter to paint your walls, the painter must be competent to paint your walls no matter what his skin color is. So, the "painter" is a contract between you and the person you hire to paint your walls. With this contract concept, you don't have to hire a specific person to do your painting job, you can hire any qualified painter to do it. In OOP, this is called loosely coupled. This is very important for writing extendable, maintainable, testable software.
       Following is a very simple example to show how interface works. We have a IPlan interface for Customer, there are two classes implementing IPlan, named PlanBasic and PlanStandard. Different customers can have different plan. Let's take a look at the code in C#:
       The IPlan interface:
       public interface IPlan
    {
        string PlanName { get;}
        float getMonthlyPayment();
    }

       PlanBasic and PlanStandard:
       public class PlanBasic : IPlan
    {
        public string PlanName
        {
            get
            {
                return "Basic Plan";
            }
        }

        public float getMonthlyPayment()
        {
            float ret = 9.99f;
            return ret;
        }
    }

       public class PlanStandard : IPlan
    {
        public string PlanName
        {
            get
            {
                return "Standard Plan";
            }
        }

        public float getMonthlyPayment()
        {
            float ret = 29.99f;
            return ret;
        }
    }

       The Customer class that is the consumer class of contract IPlan:
       public class Customer
    {
        private string name;
        private IPlan plan;

        public string Name
        {
            get
            {
                return name;
            }
        }

        public Customer(string _name, IPlan _plan)
        {
            name = _name;
            plan = _plan;
        }

        public float getMonthlyPayment()
        {
           return plan.getMonthlyPayment();
        }

        public override string ToString()
        {
            return "Name: " + name + " Plan: " + plan.PlanName + " Monthly Payment: " + getMonthlyPayment();
        }
    }

       Let's write an unit test code to test the interface pattern:
       [TestMethod]
        public void InterfaceTest()
        {
            Customer customer = new Customer("John Smith", new PlanBasic());
            Assert.AreEqual("Name: John Smith Plan: Basic Plan Monthly Payment: 9.99", customer.ToString());

            customer = new Customer("John Doe", new PlanStandard());
            Assert.AreEqual("Name: John Doe Plan: Standard Plan Monthly Payment: 29.99", customer.ToString());
        }
       You can see the customer class don't have to know any information about any specific plan when it is written.

No comments: