Factory Patterns

来源:互联网 发布:n9 软件 编辑:程序博客网 时间:2024/05/21 14:53

What is a factory? A factory is a place where objects are created.
1. Factory patterns are examples of creational patterns.
2. Creational patterns abstract the object instantiation process.
    They hide how objects are created and help make the overall system independent of how its objects are created and   
    
composed.
3. Class creational patterns focus on the use of inheritance to decide the object to be instantiated.
    Factory Method
4. Object creational patterns focus on the delegation of the instantiation to another object.
    Abstract Factory
5. All OO languages have an idiom for object creation. In Java this idiom is the new operator. Creational patterns allow 
   
us to write methods that create new objects without explicitly using the new operator. This allows us to write methods
    that
can instantiate different objects and that can be extended to instantiate other newly-developed objects, all without
   
modifying the method's code! (Quick! Name the principle involved here!).

                                                               The Factory Method Pattern

Intent
          Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets
         
a  class defer instantiation to subclasses.
Motivation
         Consider the following framework:
        
       The CreateDocument() method is a factory method.
Applicability
       Use the Factory Method pattern in any of the following situations:
            A class can't anticipate the class of objects it must create.
            A class wants its subclasses to specify the objects it creates.
Structure
      

Participants
       Product
            Defines the interface for the type of objects the factory method creates.
       ConcreteProduct
            Implements the Product interface.
       Creator
            Declares the factory method, which returns an object of type Product.
       ConcreteCreator
            Overrides the factory method to return an instance of a ConcreteProduct.
Collaborations
       Creator relies on its subclasses to implement the factory method so that it returns an instance of the appropriate     

       ConcreteProduct.
So what exactly does it mean when we say that "the Factory Method Pattern lets subclasses decide which class to instantiate?"
        It means that Creator class is written without knowing what actual ConcreteProduct class will be instantiated. The  
       
ConcreteProduct class which is instantiated is determined solely by which ConcreteCreator subclass is instantiated 
       
and used by the application.
        It does not mean that somehow the subclass decides at runtime which ConreteProduct class to create.
Consequences
        Benefits
                Code is made more flexible and reusable by the elimination of instantiation of application-specific classes.
                Code deals only with the interface of the Product class and can work with any ConcreteProduct class that      
               
supports this interface.
         Liabilities
                Clients might have to subclass the Creator class just to instantiate a particular ConcreteProduct.
Implementation Issues
          Creator can be abstract or concrete.
          Should the factory method be able to create multiple kinds of products? If so, then the factory method has a 
          parameter (possibly used in an if-else!) to decide what object to create.

                                                              The Abstract Factory Pattern

Intent
          Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
          The Abstract Factory pattern is very similar to the Factory Method pattern.One difference between the two is that   
          with the Abstract Factory pattern, a class delegates the responsibility of object instantiation to another object via 
          composition whereas the Factory Method pattern uses inheritance and relies on a subclass to handle the desired 
          object instantiation.
          Actually, the delegated object frequently uses factory methods to perform the instantiation!
Motivation
          A GUI toolkit that supports multiple look-and-feels:
        
Applicability
        Use the Abstract Factory pattern in any of the following situations:
             A system should be independent of how its products are created,composed, and represented.
             A class can't anticipate the class of objects it must create.
             A system must use just one of a set of families of products.
             A family of related product objects is designed to be used together, and you need to enforce this constraint.
Structure

           
Participants
            AbstractFactory
                  Declares an interface for operations that create abstract product objects.
            ConcreteFactory
                  Implements the operations to create concrete product objects.
            AbstractProduct
                  Declares an interface for a type of product object.
            ConcreteProduct
                  Defines a product object to be created by the corresponding concrete factory.
                  Implements the AbstractProduct interface.
            Client
                  Uses only interfaces declared by AbstractFactory and AbstractProduct classes.
Collaborations
            Normally a single instance of a ConcreteFactory class is created at runtime.(This is an example of the Singleton 
            Pattern.) This concrete factory creates product objects having a particular implementation. To create different 
            product objects, clients should use a different concrete factory.
            AbstractFactory defers creation of product objects to its ConcreteFactory.
Consequences
            Benefits
                   Isolates clients from concrete implementation classes.
                   Makes exchanging product families easy, since a particular concrete factory can support a complete family of  
                   products.
                   Enforces the use of products only from one family.
            Liabilities
                   Supporting new kinds of products requires changing the AbstractFactory interface.
Implementation Issues
            How many instances of a particular concrete factory should there be?
                   An application typically only needs a single instance of a particular concrete factory.
                   Use the Singleton pattern for this purpose
            How can the factories create the products?
                   Factory Methods
                   Factories
            How can new products be added to the AbstractFactory interface?
                   AbstractFactory defines a different method for the creation of each product it can produce.
                   We could change the interface to support only a make(String kindOfProduct) method.

Factory Pattern is a well known pattern which will help you to create objects when the following scenario may arrive.

 
Suppose we have a factory of cars which builds cars of type Ford, Ambassador, Mclaren, Ferrari.  The existing code has a method CreateCar() that takes in cartype as an argument and returns the required Car object. The existing code may be as follows….
 
           public enum CarType
              {
                      Ford=0,
                      Ambassador=1,
                      Mclaren=2,
                      Ferrari=3  
              }
 
              public Car(CarType cartype)
              {
                        if(cartype==CarType.Ford)
                        {
                                    // return Ford object
                         }
                        else if(cartype==CarType.Ambassador)
                        {
                                    //return Ambassador object
                         }
                              …
                              …
                              …
                  }    
 
The above code works pretty well as of now. But it has problems in terms of scalability and maintainability. If now we need to increase the type of cars available, the only way we can do that is to keep on increasing the number of if/else-if constructs. This produces more of un-maintainable code. Here comes the need of Factory Pattern.
 
Encapsulating the logic inside a CarFactory solves a part of the problem , but our factory also need to be both scalable and maintainable in the sense that it needs to provide a generic solution to creational logic , and not just the current workflow scope.
 
Now we are increasing our range of cars , as told before. Therefore to start of with are increasing the enum items.
 
             enum CarType
                 {
                          Ford,
                          Mitsubishi,
                         Ambassador,
                         Peugot
                 }
 
Now we create the required classes
 
      public abstract class Car
      {
      }
 
      public class Ford:Car
      {
           
      }
 
      public class Mitsubishi:Car
      {
           
      }
      public class Ambassador:Car
      {
           
      }
      public class Peugot:Car
      {
           
      }
 
Car here is an abstract class that is being inherited by the child classes whose instance we are trying to create.
 
Now we create the actual CarFactory.
 
      class CarFactory
      {
            Hashtable _registeredcars = new Hashtable();
            Hashtable _loadedcars = new Hashtable();
 
            ///<summary>
            /// Asscociating the CarType with the actual object
            ///</summary>
            ///<param name="cartype"></param>
            ///<param name="car"></param>
            public void Register(CarType cartype,Type car)
            {
                  _registeredcars.Add(cartype,car);
            }
 
            public void Register(string cartype,Type car)
            {
                  _registeredcars.Add(cartype,car);
            }
            public Car CreateCar(CarType cartype)
            {
                  if(_loadedcars[cartype]==null)
                        LoadCar();
                  return (Car)_loadedcars[cartype];
            }
 
            public void LoadCar()
            {
                  foreach(DictionaryEntry obj in _registeredcars)
                  {
                        Type type = (Type)obj.Value;
                        //  could have used Activator class
                       ConstructorInfo info = type.GetConstructor(new Type[] {});
                       _loadedcars.Add(obj.Key,(Car)info.Invoke(new object[]{}));
                  }
            }
      }
 
 
The CarFactory class consists of two Hashtables registeredcars and loadedcars.
The Register method add the registerd cars to the hashtable. This is the full list of objects that you can create out of this factory. It is quite evident from the Register method that it adds a cartype and car in the Hashtable and performs the logical connection between the two.
 
The CreateCar method takes a cartype as argument and returns a car object. While creating a car it checks whether the asked-for car object is already loaded, it returns the object from the loadedcars Hashtable, otherwise it first loads it and then returns the object.
 
The LoadCar method does the main job in creating the asked-for car object and returning it. It loops in the registeredcars Hashtable to check whether the object is there , already registered in the Hashtable. It uses Reflection to create the type and adds it in the loadedcars Hashtable.
 
Now as the factory is implemented , it start using it …
 
      static void Main(string[] args)
      {
                  CarFactory factory = new CarFactory();
                 
                 
                  //registering cars
factory.Register(CarType.Ambassador,typeof(Ambassador));
                  factory.Register(CarType.Ford,typeof(Ford));
 
                  Car _car = factory.CreateCar(CarType.Ford);
                  Console.WriteLine(_car.GetType().ToString());
 
                  Console.ReadLine();
 
        }
 
The cars that are needed are first registered, using a call to the Register method. Then we create the reuired car object by calling the Createcar() and passing the suitable cartype.
 
You can clearly see that any object that is registered ,can be created on runtime without the use of the earlier if-else… blocks.
原创粉丝点击