Wednesday, February 29, 2012

Design Patterns: Factory

       During software development, you may need to create an instance of a set of classes implement the same interface. It depends on runtime conditions / settings to create which concrete class instance. If you test the condition / settings each time when you need to create the instance. The logic that selects the class of instance will be scattered everywhere in your code. Once the select logic is changed, you have to change everywhere the logic is. You can use Factory pattern to resolve this problem.

       For example, we have a IVehicle interface:

       public interface IVehicle
    {
        void drive();
    }

       There are 3 classes Car, Truck, and Bus implement IVehicle interface:

       public class Car : IVehicle
    {
        public void drive() { }
    }

    public class Truck : IVehicle
    {
        public void drive() { }
    }

    public class Bus : IVehicle
    {
        public void drive() { }
    }

       We use a factory class VechicleFactory to read system settings and create IVechicle instance:

       public class VehicleFactory
    {
        public const int VEHICLE_TYPE_CAR = 1;
        public const int VEHICLE_TYPE_TRUCK = 2;
        public const int VEHICLE_TYPE_BUS = 3;

        public IVehicle createVehicle()
        {
            IVehicle ret = null;

            int type = getVehicleType();

            switch (type)
            {
                case VEHICLE_TYPE_CAR:
                    ret = new Car();
                    break;

                case VEHICLE_TYPE_TRUCK:
                    ret = new Truck();
                    break;

                case VEHICLE_TYPE_BUS:
                    ret = new Bus();
                    break;
            }

            return ret;
        }

        private int getVehicleType()
        {
            SystemSettings settings = SystemSettings.getInstance();
            return settings.VehicleType;
        }
    }

       To simplify the sample, we just hard code the vehicle type in System settings class, which is of singleton pattern in my previous blog:
       public class SystemSettings
    {
        private static int instanceNum = 0;
        private static SystemSettings settings;

        private int vehicleType = VehicleFactory.VEHICLE_TYPE_CAR;

        private SystemSettings() { instanceNum++; }
        public static SystemSettings getInstance()
        {
            if (settings == null)
            {
                settings = new SystemSettings();
            }
            return settings;
        }

        public static int InstanceNumber
        {
            get
            {
                return instanceNum;
            }
        }

        public int VehicleType
        {
            get
            {
                return vehicleType;
            }
        }
    }

       We write unit test code to test the factory pattern:
       [TestMethod]
        public void FactoryTest()
        {
            VehicleFactory factory = new VehicleFactory();

            IVehicle vehicle = factory.createVehicle();

            Assert.IsTrue(vehicle is Car);
        }
 
       You can see the client code don't have to know how to select the vehicle type to create the vehicle instance. The client just need to use factory to create the instance.

No comments: