Why Using Factory
“Creates objects without exposing the instantiation logic to the client. It refers to the newly created object through a common interface.” This is exactly Factory pattern.
Software design principles represent a set of guidelines. These guidelines help us to create a good design. There are some characteristics of bad design,
1. Hard to change: changes affect too many other part of the system.
2. System breaks while changing.
3. Hard to reuse.
I am going to start with 3 tier architecture. Basically we know in three tier architecture the UI code is in the client section, business layer is nothing but business classes which has the business validation and the data access layer does all the database operations.
If we study these 3 sections most changes happening in business layer. Business rules change time by time. Client changes depend on user interface but it won’t be as much as business layer. Then data layer, compared to other layers least changes coming here. Because migrate from one database to other is not urgent basis.
Dependency:
1. High Level modules should not depend on Low Level modules. Both should depend on abstractions.
2. Abstraction should not depend on details, details should depend on abstraction.
We should decouple high level modules from low level modules, introducing an abstraction layer between the high level classes and low level classes. Furthermore it inverts the dependency: instead of writing our abstractions based on details, and then we should write the details based on abstractions. In the classical way when a software module (class, framework etc) need some other module, it initializes and holds a direct reference to it. This will make the 2 modules tight coupled. In order to decouple them the first module will provide a hook (a property, parameter, etc) and an external module controlling the dependencies will inject the reference to the second one. By applying the Dependency Inversion the modules can be easily changed by other modules just changing the dependency module. Factories and Abstract Factories can be used as dependency frameworks.
Fat Interface:
If we write interface we should add methods that should be there in class. Client should not be forced to depend upon interface that they don’t use.
Eg: Workers for that two methods work () and Eat (). There two type of workers efficient and average. Both types of workers need daily Lunch break to eat. But now some robots came in the company they work as well , but they don't eat so they don't need a launch break. One on side the new Robot class need to implement the IWorker interface because robots works. On the other side, the don't have to implement it because they don't eat.
Interface IWorker{
void work();
void Eat();
}
class Worker implements IWorker{
Public void work()
{//Code
}
Public void Eat()
{/Code
}
}
class SuperWorker implements IWorker{
{//Code
}
Public void Eat()
{/Code
}
}
class Manager {
IWorker worker;
IWorker worker;
public void setWorker(IWorker w) {
worker=w;
}
worker=w;
}
public void manage() {
worker.work();
} ………………………. Etc
worker.work();
} ………………………. Etc
the new Robot class is forced to implement the eat method. We can write a dummy class which does nothing(let's say a launch break of 1 second daily), and can have undesired effects in the application(For example the reports seen by managers will report more lunches taken than the number of people).
For this we can split the IWorker interface in 2 different interfaces the new Robot class is no longer forced to implement the eat method. Also if we need another functionality for the robot like recharging we create another interface IRechargeble with a method recharge.
interface IWorker extends Feedable, Workable {
}
interface IWorkable {
public void work();
}
interface IFeedable{
public void eat();
}
}
interface IWorkable {
public void work();
}
interface IFeedable{
public void eat();
}
class Worker implements IWorkable, IFeedable{
public void work() {// ....
}
public void eat() {//....
}
}
class Robot implements IWorkable{
public void work() {// .... etc…
}
}
public void work() {// ....
}
public void eat() {//....
}
}
class Robot implements IWorkable{
public void work() {// .... etc…
}
}
This require additional time and effort spent to apply it during the design time and increase the complexity of code. But it produce a flexible design. If we are going to apply it more than is necessary it will result a code containing a lot of interfaces with single methods, so applying should be done based on experience and common sense in identifying the areas where extension of code are more likely to happens in the future.
Change Classes:
If we have 2 reasons to change for a class, we have to split the functionality in two classes. Each class will handle only one responsibility and on future if we need to make one change we are going to make it in the class which handles it. When we need to make a change in a class having more responsibilities the change might affect the other functionality of the classes.
If we need to extend the behavior of class then don’t have to change the class instead of that extend that class. This applicable for modules, packages, libraries etc. So better use Abstract Classes and concrete classes for implementing their behavior. This will enforce having Concrete Classes extending Abstract Classes instead of changing them. Also we must make sure that new derived classes are extending the base classes without changing their behavior. The new derived classes should be able to replace the base classes without any change in the code.
Factory Pattern
The implementation is really simple
· The client needs a product, but instead of creating it directly using the new operator, it asks the factory object for a new product, providing the information about the type of object it needs.
· The factory instantiates a new concrete product and then returns to the client the newly created product(casted to abstract product class).
· The client uses the products as abstract products without being aware about their concrete implementation.
Eg: a graphical application works with shapes. In our implementation the drawing framework is the client and the shapes are the products. All the shapes are derived from an abstract shape class (or interface). The Shape class defines the draw and move operations which must be implemented by the concrete shapes. Let's assume a command is selected from the menu to create a new Circle. The framework receives the shape type as a string parameter, it asks the factory to create a new shape sending the parameter received from menu. The factory creates a new circle and returns it to the framework, casted to an abstract shape. Then the framework uses the object as casted to the abstract class without being aware of the concrete object type.
The advantage is obvious: New shapes can be added without changing a single line of code in the framework(the client code that uses the shapes from the factory).
Class Registration - using reflection
We can register new product classes to the factory without even changing the factory itself. For creating objects inside the factory class without knowing the object type we keep a map between the productID and the class type of the product. In this case when a new product is added to the application it has to be registered to the factory. This operation doesn't require any change in the factory class code
class ProductFactory
{
{
private HashMap m_RegisteredProducts = new HashMap();
public void registerProduct (String productID, Class productClass)
{
public void registerProduct (String productID, Class productClass)
{
m_RegisteredProducts.put(productID, productClass);
}
}
public Product createProduct(String productID)
{
{
Class productClass = (Class)m_RegisteredProducts.get(productID);
Constructor productConstructor = cClass.getDeclaredConstructor(new Class[] { String.class });
return (Product)productConstructor.newInstance(new Object[] { });
}
Constructor productConstructor = cClass.getDeclaredConstructor(new Class[] { String.class });
return (Product)productConstructor.newInstance(new Object[] { });
}
}
We can put the registration code anywhere in our code, but a convenient place is inside the product class in a static constructor
1. Registration done outside of product classes:
public static void main(String args[]){
Factory.instance().registerProduct("ID1", OneProduct.class);
}
Factory.instance().registerProduct("ID1", OneProduct.class);
}
2. Registration done inside the product classes:
class OneProduct extends Product
{
static {
{
static {
Factory.instance().registerProduct("ID1",OneProduct.class);
}
...
}
}
...
}
We have to make sure that the concrete product classes are loaded before they are required by the factory for registration (if they are not loaded they will not be registered in the factory and createProduct will return null). To ensure it we are going to use the Class.forName method right in the static section of the main class. This section is executed right after the main class is loaded. Class.forName is supposed to return a Class instance of the indicated class. If the class is not loaded by the compiler yet, it will be loaded when the Class.forName is invoked. Consequently the static block in each class will be executed when each class is loaded:
class Main
{
static
{
try
{
{
static
{
try
{
Class.forName("OneProduct");
Class.forName("AnotherProduct");
}
catch (ClassNotFoundException any)
{
any.printStackTrace();
}
Class.forName("AnotherProduct");
}
catch (ClassNotFoundException any)
{
any.printStackTrace();
}
}
public static void main(String args[]) throws PhoneCallNotRegisteredException
{
...
}
}
public static void main(String args[]) throws PhoneCallNotRegisteredException
{
...
}
}
This reflection implementation has its own drawbacks. The main one is performance. When the reflection is used the performance on code involving reflection can decrease even to 10% of the poerfomance of a non reflection code. Another issue is that not all the programming languages provide reflection mechanism.
Class Registration - avoiding reflection
As we saw in the previous paragraph the factory object uses internally a HashMap to keep the mapping between parameters (in our case Strings) and concrete products class. The registration is made from outside of the factory and because the objects are created using reflection the factory is not aware of the objects types.
We don't want to use reflection but in the same time we want to have a reduced coupling between the factory and concrete products. Since the factory should be unaware of products we have to move the creation of objects outside of the factory to an object aware of the concrete products classes. That would be the concrete class itself.
We add a new abstract method in the product abstract class. Each concrete class will implement this method to create a new object of the same type as itself. We also have to change the registration method such that we'll register concrete product objects instead of Class objects.
abstract class Product
{
public abstract Product createProduct();
...
}
{
public abstract Product createProduct();
...
}
class OneProduct extends Product
{
...
static
{
ProductFactory.instance().registerProduct("ID1", new OneProduct());
}
public OneProduct createProduct()
{
return new OneProduct();
}
...
}
{
...
static
{
ProductFactory.instance().registerProduct("ID1", new OneProduct());
}
public OneProduct createProduct()
{
return new OneProduct();
}
...
}
class ProductFactory
{
public void registerProduct(String productID, Product p) {
m_RegisteredProducts.put(productID, p);
}
public Product createProduct(String productID){
((Product)m_RegisteredProducts.get(productID)).createProduct();
}
}
{
public void registerProduct(String productID, Product p) {
m_RegisteredProducts.put(productID, p);
}
public Product createProduct(String productID){
((Product)m_RegisteredProducts.get(productID)).createProduct();
}
}
Client à Ask for new obj à Factory ß Concrete Factory
^
|
Client à Uses à Interface (Product) <-- Concrete Product
This implementation represents an alternative for the class registration implementation. Let's assume we need to add a new product to the application. For the procedural switch-case implementation we need to change the Factory class, while in the class registration implementation all we need is to register the class to the factory without actually modifying the factory class. For sure this is a flexible solution.
The procedural implementation is the classical bad example for the Open-Close Principle. As we can see there the most intuitive solution to avoid modifying the Factory class is to extend it.
This is the classic implementation of the factory method pattern. There are some drawbacks over the class registration implementation and not so many advantages:
· + The derived factory method can be changed to perform additional operations when the objects are created (maybe some initialization based on some global parameters ...).
· - The factory can not be used as a singleton.
· - Each factory has to be initialized before using it.
· - More difficult to implement.
· - If a new object has to be added a new factory has to be created.
Anyway, this classic implementation has the advantage that it will help us understanding the Abstract Factory design pattern.
Factory method pattern (Virtual Constructor)
The factory method pattern is an object-oriented design pattern to implement the concept of factories. Like other creational patterns, it deals with the problem of creating objects (products) without specifying the exact class of object that will be created. The essence of the Factory method Pattern is to "Define an interface for creating an object, but let the classes that implement the interface decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses.
· Defines an interface for creating objects, but let subclasses to decide which class to instantiate
· Refers to the newly created object through a common interface
It defines an interface for creating an object, but leaves the choice of its type to the subclasses, creation being deferred at run-time. A simple real life example of the Factory Method is the hotel. When staying in a hotel you first have to check in. The person working at the front desk will give you a key to your room after you've paid for the room you want and this way he can be looked at as a ?room? factory. While staying at the hotel, you might need to make a phone call, so you call the front desk and the person there will connect you with the number you need, becoming a ?phone-call? factory, because he controls the access to calls, too.
The participants classes in this pattern are:
· Product defines the interface for objects the factory method creates.
· ConcreteProduct implements the Product interface.
· Creator(also refered as Factory because it creates the Product objects) declares the method FactoryMethod, which returns a Product object. May call the generating method for creating Product objects
· ConcreteCreator overrides the generating method for creating ConcreteProduct objects
All concrete products are subclasses of the Product class, so all of them have the same basic implementation, at some extent. The Creator class specifies all standard and generic behavior of the products and when a new product is needed, it sends the creation details that are supplied by the client to the ConcreteCreator. Having this diagram in mind, it is easy for us now to produce the code related to it. Here is how the implementation of the classic Factory method should look:
Public interface Product { ------ }
public abstract class Creator
{
public void anOperation()
{
Product product = factoryMethod();
}
protected abstract Product factoryMethod();
}
public class ConcreteProduct implements Product { ---- }
public class ConcreteCreator extends Creator
{
protected Product factoryMethod()
{
return new ConcreteProduct();
}
}
public class Client
{
public static void main( String arg[] )
{
Creator creator = new ConcreteCreator();
creator.anOperation();
}
}
Factory Method à Produce à Products
Product ß Concrete Creator (+FactoryMethod (): Product) à Creator (+FactoryMethod (): Product)
The creation of an object often requires complex processes not appropriate to include within a composing object. The object's creation may lead to a significant duplication of code, may require information not accessible to the composing object, may not provide a sufficient level of abstraction, or may otherwise not be part of the composing object's concerns. The factory method design pattern handles these problems by defining a separate method for creating the objects, which subclasses can then override to specify the derived type of product that will be created. Some of the processes required in the creation of an object include determining which object to create, managing the lifetime of the object, and managing specialized build-up and tear-down concerns of the object. Outside the scope of design patterns, the term factory method can also refer to a method of a factory whose main purpose is creation of objects.
Although the motivation behind the factory method pattern is to allow subclasses to choose which type of object to create, there are other benefits to using factory methods, many of which do not depend on subclassing. Therefore, it is common to define "factory methods" that are not polymorphic to create objects in order to gain these other benefits. Such methods are often static.
When we have to use Factory?
- The creation of an object precludes its reuse without significant duplication of code.
- The creation of an object requires access to information or resources that should not be contained within the composing class.
- The lifetime management of the generated objects must be centralized to ensure a consistent behavior within the application.
Limitations:
There are three limitations associated with the use of the factory method. The first relates to refactoring existing code (an existing class to use factories breaks existing clients); the other two relate to extending (Any subclass must invoke the inherited constructor, but this cannot be done if that constructor is private) class. Then the third limitation is that if we extend like making the constructor protected (risky but feasible), the sub class must provide re implementation of all factory methods with exactly the same signature.
Abstract factory pattern
Modularization is a big issue in today's programming. Programmers all over the world are trying to avoid the idea of adding code to existing classes in order to make them support encapsulating more general information. Take the case of a information manager which manages phone number. Phone numbers have a particular rule on which they get generated depending on areas and countries. If at some point the application should be changed in order to support adding numbers form a new country, the code of the application would have to be changed and it would become more and more complicated.
In order to prevent it, the Abstract Factory design pattern is used. Using this pattern a framework is defined, which produces objects that follow a general pattern and at runtime this factory is paired with any concrete factory to produce objects that follow the pattern of a certain country. In other words, the Abstract Factory is a super-factory which creates other factories (Factory of factories).
“Abstract Factory offers the interface for creating a family of related objects, without explicitly specifying their classes.“
The classes that participate to the Abstract Factory pattern are:
· AbstractFactory - declares a interface for operations that create abstract products.
· ConcreteFactory - implements operations to create concrete products.
· AbstractProduct - declares an interface for a type of product objects.
· Product - defines a product to be created by the corresponding ConcreteFactory; it implements the AbstractProduct interface.
· Client - uses the interfaces declared by the AbstractFactory and AbstractProduct classes.
The AbstractFactory class is the one that determines the actual type of the concrete object and creates it, but it returns an abstract pointer to the concrete object just created. This determines the behavior of the client that asks the factory to create an object of a certain abstract type and to return the abstract pointer to it, keeping the client from knowing anything about the actual creation of the object.
The fact that the factory returns an abstract pointer to the created object means that the client doesn't have knowledge of the object's type. This implies that there is no need for including any class declarations relating to the concrete type, the client dealing at all times with the abstract type. The objects of the concrete type, created by the factory, are accessed by the client only through the abstract interface.
The second implication of this way of creating objects is that when the adding new concrete types is needed, all we have to do is modify the client code and make it use a different factory, which is far easier than instantiating a new type, which requires changing the code wherever a new object is created.
The classic implementation for the Abstract Factory pattern is the following:
The abstract factory pattern is a software design pattern that provides a way to encapsulate a group of individual factories that have a common theme. In normal usage, the client software creates a concrete implementation of the abstract factory and then uses the generic interfaces to create the concrete objects that are part of the theme. The client does not know (or care) which concrete objects it gets from each of these internal factories, since it uses only the generic interfaces of their products. This pattern separates the details of implementation of a set of objects from their general usage.
An example of this would be an abstract factory class
DocumentCreator
that provides interfaces to create a number of products (e.g. createLetter()
and createResume()
). The system would have any number of derived concrete versions of the DocumentCreator
class like FancyDocumentCreator
or ModernDocumentCreator
, each with a different implementation of createLetter()
and createResume()
that would create a corresponding object like FancyLetter
or ModernResume
. Each of these products is derived from a simple abstract class like Letter
or Resume
of which the client is aware. The client code would get an appropriate instance of the DocumentCreator
and call its factory methods. Each of the resulting objects would be created from the same DocumentCreator
implementation and would share a common theme (they would all be fancy or modern objects). The client would need to know how to handle only the abstract Letter
or Resume
class, not the specific version that it got from the concrete factory.
Example, this time more simple and easier to understand, is the one of a pizza factory, which defines method names and returns types to make different kinds of pizza. The abstract factory can be named AbstractPizzaFactory, RomeConcretePizzaFactory and MilanConcretePizzaFactory being two extensions of the abstract class. The abstract factory will define types of toppings for pizza, like pepperoni, sausage or anchovy, and the concrete factories will implement only a set of the toppings, which are specific for the area and even if one topping is implemented in both concrete factories, the resulting pizzas will be different subclasses, each for the area it was implemented in.
A factory is the location or a concrete class in the code at which objects are constructed. The intent in employing the pattern is to insulate the creation of objects from their usage. This allows for new derived types to be introduced with no change to the code that uses the base class.
Use of this pattern makes it possible to interchange concrete implementations without changing the code that uses them, even at runtime. However, employment of this pattern, as with similar design patterns, may result in unnecessary complexity and extra work in the initial writing of code. Used correctly the "extra work" pays off in the second implementation of the factory.
“The essence of the Abstract Factory method Pattern is to "Provide an interface for creating families of related or dependent objects without specifying their concrete classes".
The factory determines the actual concrete type of object to be created, and it is here that the object is actually created (in C++, for instance, by the new operator). However, the factory only returns an abstract pointer to the created concrete object.
This insulates client code from object creation by having clients ask a factory object to create an object of the desired abstract type and to return an abstract pointer to the object.
As the factory only returns an abstract pointer, the client code (that requested the object from the factory) does not know – and is not burdened by – the actual concrete type of the object that was just created. However, the type of a concrete object (and hence a concrete factory) is known by the abstract factory; for instance, the factory may read it from a configuration file. The client has no need to specify the type, since it has already been specified in the configuration file. In particular, this means:
- The client code has no knowledge whatsoever of the concrete type, not needing to include any header files or class declarations related to it. The client code deals only with the abstract type. Objects of a concrete type are indeed created by the factory, but the client code accesses such objects only through their abstract interface.
- Adding new concrete types is done by modifying the client code to use a different factory, a modification that is typically one line in one file. (The different factory then creates objects of a different concrete type, but still returns a pointer of the same abstract type as before – thus insulating the client code from change.) This is significantly easier than modifying the client code to instantiate a new type, which would require changing every location in the code where a new object is created (as well as making sure that all such code locations also have knowledge of the new concrete type, by including for instance a concrete class header file). If all factory objects are stored globally in a singleton object, and all client code goes through the singleton to access the proper factory for object creation, then changing factories is as easy as changing the singleton object.
using System;
using System.Configuration;
namespace AbstractFactory
{
public interface IButton
{
void Paint();
}
public interface IGUIFactory
{
IButton CreateButton();
}
public class OSXButton : IButton
{
public void Paint()
{
System.Console.WriteLine("I'm an OSXButton");
}
}
public class WinButton : IButton
{
public void Paint()
{
System.Console.WriteLine("I'm a WinButton");
}
}
public class OSXFactory : IGUIFactory
{
IButton IGUIFactory.CreateButton()
{
return new OSXButton();
}
}
public class WinFactory : IGUIFactory
{
IButton IGUIFactory.CreateButton()
{
return new WinButton();
}
}
public class Application
{
public Application(IGUIFactory factory)
{
IButton button = factory.CreateButton();
button.Paint();
}
}
public class ApplicationRunner
{
static IGUIFactory CreateOsSpecificFactory()
{
// Contents of App.Config associated with this C# project
//<?xml version="1.0" encoding="utf-8" ?>
//<configuration>
// <appSettings>
// <!-- Uncomment either Win or OSX OS_TYPE to test -->
// <add key="OS_TYPE" value="Win" />
// <!-- <add key="OS_TYPE" value="OSX" /> -->
// </appSettings>
//</configuration>
string sysType = ConfigurationSettings.AppSettings["OS_TYPE"];
if (sysType == "Win")
{
return new WinFactory();
}
else
{
return new OSXFactory();
}
}
static void Main(string[] args)
{
new Application(CreateOsSpecificFactory());
Console.ReadLine();
}
}
}
Specific problems and implementation
The Abstract Factory pattern has both benefits and flaws. On one hand it isolates the creation of objects from the client that needs them, giving the client only the possibility of accessing them through an interface, which makes the manipulation easier. The exchanging of product families is easier, as the class of a concrete factory appears in the code only where it is instantiated. Also if the products of a family are meant to work together, the Abstract Factory makes it easy to use the objects from only one family at a time. On the other hand, adding new products to the existing factories is difficult, because the Abstract Factory interface uses a fixed set of products that can be created. That is why adding a new product would mean extending the factory interface, which involves changes in the AbstractFactory class and all its subclasses. This section will discuss ways of implementing the pattern in order to avoid the problems that may appear.
Factories as singletons
An application usually needs only one instance of the ConcreteFactory class per family product. This means that it is best to implement it as a Singleton.
Creating the products
The AbstractFactory class only declares the interface for creating the products. It is the task of the ConcreteProduct class to actually create the products. For each family the best idea is applying the Factory Method design pattern. A concrete factory will specify its products by overriding the factory method for each of them. Even if the implementation might seem simple, using this idea will mean defining a new concrete factory subclass for each product family, even if the classes are similar in most aspects.
For simplifying the code and increase the performance the Prototype design pattern can be used instead of Factory Method, especially when there are many product families. In this case the concrete factory is initiated with a prototypical instance of each product in the family and when a new one is needed instead of creating it, the existing prototype is cloned. This approach eliminates the need for a new concrete factory for each new family of products.
Extending the factories
The operation of changing a factory in order for it to support the creation of new products is not easy. What can be done to solve this problem is, instead of a CreateProduct method for each product, to use a single Create method that takes a parameter that identifies the type of product needed. This approach is more flexible, but less secure. The problem is that all the objects returned by the Create method will have the same interface, that is the one corresponding to the type returned by the Create method and the client will not always be able to correctly detect to which class the instance actually belongs.
Hot Points:
· AbstractFactory class declares only an interface for creating the products. The actual creation is the task of the ConcreteProduct classes, where a good approach is applying the Factory Method design pattern for each product of the family.
· Extending factories can be done by using one Create method for all products and attaching information about the type of product needed.
Comments
Post a Comment