Creational Design Patterns
Singleton Pattern
Motivation
Sometimes it's important to have only one instance for a class. For example, in a system there should be only one window manager (or only a file system or only a print spooler). Usually singletons are used for centralized management of internal or external resources and they provide a global point of access to themselves.The singleton pattern is one of the simplest design patterns: it involves only one class which is responsible to instantiate itself, to make sure it creates not more than one instance; in the same time it provides a global point of access to that instance. In this case the same instance can be used from everywhere, being impossible to invoke directly the constructor each time.
Intent
- Ensure that only one instance of a class is created.
- Provide a global point of access to the object.
Implementation
The implementation involves a static member in the "Singleton" class, a private constructor and a static public method that returns a reference to the static member.The Singleton Pattern defines a getInstance operation which exposes the unique instance which is accessed by the clients. getInstance() is is responsible for creating its class unique instance in case it is not created yet and to return that instance.
class Singleton { private static Singleton instance; private Singleton() { ... } public static synchronized Singleton getInstance() { if (instance == null) instance = new Singleton(); return instance; } ... public void doSomething() { ... } } |
The getInstance method is used also to provide a global point of access to the object and it can be used in the following manner:
Singleton.getInstance().doSomething(); |
Applicability & Examples
According to the definition the singleton pattern should be used when there must be exactly one instance of a class, and when it must be accessible to clients from a global access point. Here are some real situations where the singleton is used:Example 1 - Logger Classes
The Singleton pattern is used in the design of logger classes. This classes are ussualy implemented as a singletons, and provides a global logging access point in all the application components without being necessary to create an object each time a logging operations is performed.Example 2 - Configuration Classes
The Singleton pattern is used to design the classes which provides the configuration settings for an application. By implementing configuration classes as Singleton not only that we provide a global access point, but we also keep the instance we use as a cache object. When the class is instantiated( or when a value is read ) the singleton will keep the values in its internal structure. If the values are read from the database or from files this avoids the reloading the values each time the configuration parameters are used.Example 3 - Accesing resources in shared mode
It can be used in the design of an application that needs to work with the serial port. Let's say that there are many classes in the application, working in an multi-threading environment, which needs to operate actions on the serial port. In this case a singleton with synchronized methods could be used to be used to manage all the operations on the serial port.Example 4 - Factories implemented as Singletons
Let's assume that we design an application with a factory to generate new objects(Acount, Customer, Site, Address objects) with their ids, in an multithreading environment. If the factory is instantiated twice in 2 different threads then is possible to have 2 overlapping ids for 2 different objects. If we implement the Factory as a singleton we avoid this problem. Combining Abstract Factory or Factory Method and Singleton design patterns is a common practice.Specific problems and implementation
Thread-safe implementation for multi-threading use.
A robust singleton implementation should work in any conditions. This is why we need to ensure it works when multiple threads uses it. As seen in the previous examples singletons can be used specifically in multi-threaded application to make sure the reads/writes are synchronized.Lazy instantiation using double locking mechanism.
The standard implementation shown in the above code is a thread safe implementation, but it's not the best thread-safe implementation beacuse synchronization is very expensive when we are talking about the performance. We can see that the synchronized method getInstance does not need to be checked for syncronization after the object is initialized. If we see that the singleton object is already created we just have to return it without using any syncronized block. This optimization consist in checking in an unsynchronized block if the object is null and if not to check again and create it in an syncronized block. This is called double locking mechanism.In this case case the singleton instance is created when the getInstance() method is called for the first time. This is called lazy instantiation and it ensures that the singleton instance is created only when it is needed.
//Lazy instantiation using double locking mechanism. class Singleton { private static Singleton instance; private Singleton() { System.out.println("Singleton(): Initializing Instance"); } public static Singleton getInstance() { if (instance == null) { synchronized(Singleton.class) { if (instance == null) { System.out.println("getInstance(): First time getInstance was invoked!"); instance = new Singleton(); } } } return instance; } public void doSomething() { System.out.println("doSomething(): Singleton does something!"); } } |
Early instantiation using implementation with static field
In the following implementattion the singleton object is instantiated when the class is loaded and not when it is first used, due to the fact that the instance member is declared static. This is why in we don't need to synchronize any portion of the code in this case. The class is loaded once this guarantee the uniquity of the object.Singleton - A simple example (java)
//Early instantiation using implementation with static field. class Singleton { private static Singleton instance = new Singleton(); private Singleton() { System.out.println("Singleton(): Initializing Instance"); } public static Singleton getInstance() { return instance; } public void doSomething() { System.out.println("doSomething(): Singleton does something!"); } } |
Protected constructor
It is possible to use a protected constructor to in order to permit the subclassing of the singeton. This techique has 2 drawbacks that makes singleton inheritance impractical:- First of all, if the constructor is protected, it means that the class can be instantiated by calling the constructor from another class in the same package. A possible solution to avoid it is to create a separate package for the singleton.
- Second of all, in order to use the derived class all the getInstance calls should be changed in the existing code from Singleton.getInstance() to NewSingleton.getInstance().
Multiple singleton instances if classes loaded by different classloaders access a singleton.
If a class(same name, same package) is loaded by 2 diferent classloaders they represents 2 different clasess in memory.Serialization
If the Singleton class implements the java.io.Serializable interface, when a singleton is serialized and then deserialized more than once, there will be multiple instances of Singleton created. In order to avoid this the readResolve method should be implemented. See Serializable () and readResolve Method () in javadocs.public class Singleton implements Serializable { ... // This method is called immediately after an object of this class is deserialized. // This method returns the singleton instance. protected Object readResolve() { return getInstance(); } } |
Abstract Factory and Factory Methods implemented as singletons.
There are certain situations when the a factory should be unique. Having 2 factories might have undesired effects when objects are created. To ensure that a factory is unique it should be implemented as a singleton. By doing so we also avoid to instantiate the class before using it.Hot Spot:
- Multithreading - A special care should be taken when singleton has to be used in a multithreading application.
- Serialization - When Singletons are implementing Serializable interface they have to implement readResolve method in order to avoid having 2 different objects.
- Classloaders - If the Singleton class is loaded by 2 different class loaders we'll have 2 different classes, one for each class loader.
- Global Access Point represented by the class name - The singleton instance is obtained using the class name. At the first view this is an easy way to access it, but it is not very flexible. If we need to replace the Sigleton class, all the references in the code should be changed accordinglly.
Factory Design Pattern
Motivation
The Factory Design Pattern is probably the most used design pattern in modern programming languages like Java and C#. It comes in different variants and implementations. If you are searching for it, most likely, you'll find references about the GoF patterns: Factory Method and Abstract Factory.In this article we'll describe a flavor of factory pattern commonly used nowdays. You can also check the original Factory Method pattern which is very similar.
Intent
- creates objects without exposing the instantiation logic to the client.
- refers to the newly created object through a common interface
Implementation
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.
Applicability & Examples
Probably the factory pattern is one of the most used patterns.For example 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). As it is shown in the next sections, there are certain factory implementations that allow adding new products without even modifying the factory class.
Specific problems and implementation
Procedural Solution - switch/case noob instantiation.
Those are also known as parameterized Factories. The generating method can be written so that it can generate more types of Product objects, using a condition (entered as a method parameter or read from some global configuration parameters - see abstract factory pattern) to identify the type of the object that should be created, as below:
public class ProductFactory{ public Product createProduct(String ProductID){ if (id==ID1) return new OneProduct(); if (id==ID2) return return new AnotherProduct(); ... // so on for the other Ids return null; //if the id doesn't have any of the expected values } ... } |
Class Registration - using reflection
If you can use reflection, for example in Java or .NET languages, you 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) { 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[] { }); } } |
1. Registration done outside of product classes:
public static void main(String args[]){ Factory.instance().registerProduct("ID1", OneProduct.class); } |
2. Registration done inside the product classes:
class OneProduct extends Product { static { Factory.instance().registerProduct("ID1",OneProduct.class); } ... } |
class Main { static { try { Class.forName("OneProduct"); Class.forName("AnotherProduct"); } catch (ClassNotFoundException any) { any.printStackTrace(); } } public static void main(String args[]) throws PhoneCallNotRegisteredException { ... } } |
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(); ... } class OneProduct extends Product { ... 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(); } } |
A more advanced solution - Factory design pattern with abstractions(Factory Method)
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.
Conclusion:
When you design an application just think if you really need it a factory to create objects. Maybe using it will bring unnecessary complexity in your application. If you have many objects of the same base type and you manipulate them mostly casted to abstract types, then you need a factory. If you're code should have a lot of code like the following, you should reconsider it:(if (ConcreteProduct)genericProduct typeof ) ((ConcreteProduct)genericProduct).doSomeConcreteOperation(). |
Factory Method Pattern
Motivation
Also known as Virtual Constructor, the Factory Method is related to the idea on which libraries work: a library uses abstract classes for defining and maintaining relations between objects. One type of responsibility is creating such objects. The library knows when an object needs to be created, but not what kind of object it should create, this being specific to the application using the library.The Factory method works just the same way: 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.
Intent
- 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
Implementation
The pattern basically works as shown below, in the UML diagram: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
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(); } } |
Applicability & Examples
The need for implementing the Factory Method is very frequent. The cases are the ones below:- when a class can't anticipate the type of the objects it is supposed to create
- when a class wants its subclasses to be the ones to specific the type of a newly created object
Example 1 - Documents Application.
Take into consideration a framework for desktop applications. Such applications are meant to work with documents. A framework for desktop applications contains definitions for operations such as opening, creating and saving a document. The basic classes are abstract ones, named Application and Document, their clients having to create subclasses from them in order to define their own applications. For generating a drawing application, for example, they need to define the DrawingApplication and DrawingDocument classes. The Application class has the task of managing the documents, taking action at the request of the client (for example, when the user selects the open or save command form the menu).Because the Document class that needs to be instantiated is specific to the application, the Application class does not know it in advance, so it doesn't know what to instantiate, but it does know when to instantiate it. The framework needs to instantiate a certain class, but it only knows abstract classes that can't be instantiated.
The Factory Method design pattern solves the problem by putting all the information related to the class that needs to be instantiated into an object and using them outside the framework, as you can see below
In the Application class the CreateDocument method either has a default implementation or it doesn't have any implementation at all, this operation being redefined in the MyApplication subclass so that it creates a MyDocument object and returns a reference to it.
public Document CreateDocument(String type){ if (type.isEqual("html")) return new HtmlDocument(); if (type.isEqual("proprietary")) return new MyDocument(); if (type.isEqual("pdf")) return new PdfDocument (); } |
public void NewDocument(String type){ Document doc=CreateDocument(type); Docs.add(doc); Doc.Open(); } |
Specific problems and implementation
When implementing the Factory Method design pattern some issues may appear:Definition of Creator class
If we apply the pattern to an already written code there may be problems with the way we have the Creator class already defined. There are two cases:- Creator class is abstract and generating method does not have any implementation. In this case the ConcreteCreator classes must define their own generation method and this situation usually appears in the cases where the Creator class can't foresee what ConcreteProduct it will instantiate.
- Creator class is a concrete class, the generating method having a default implementation. If this happens, the ConcreteCreator classes will use the generating method for flexibility rather than for generation. The programmer will always be able to modify the class of the objects that the Creator class implicitly creates, redefining the generation method.
Drawbacks and Benefits
Here are the benefits and drawbacks of factory method pattern:- + The main reason for which the factory pattern is used is that it introduces a separation between the application and a family of classes (it introduces weak coupling instead of tight coupling hiding concrete classes from the application). It provides a simple way of extending the family of products with minor changes in application code.
- + It provides customization hooks. When the objects are created directly inside the class it's hard to replace them by objects which extend their functionality. If a factory is used instead to create a family of objects the customized objects can easily replace the original objects, configuring the factory to create them.
- - The factory has to be used for a family of objects. If the classes doesn't extend common base class or interface they can not be used in a factory design template.
Hot Points:
The factory method is one of the most used and one of the more robust design patterns. There are only few points which have to be considered when you implement a factory method.When you design an application just think if you really need it a factory to create objects. Maybe using it will bring unnecessary complexity in your application. Anyway if you have many object of the same base type and you manipulate them mostly as abstract objects, then you need a factory. I you're code should have a lot of code like the following, reconsider it.
if (genericProduct typeof ConcreteProduct) ((ConcreteProduct)genericProduct).doSomeConcreteOperation(); |
Abstract Factory
Motivation
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).
Intent
- Abstract Factory offers the interface for creating a family of related objects, without explicitly specifying their classes.
Implementation
The pattern basically works as shown below, in the UML diagram: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 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:
abstract class AbstractProductA{ public abstract void operationA1(); public abstract void operationA2(); } class ProductA1 extends AbstractProductA{ ProductA1(String arg){ System.out.println("Hello "+arg); } // Implement the code here public void operationA1() { }; public void operationA2() { }; } class ProductA2 extends AbstractProductA{ ProductA2(String arg){ System.out.println("Hello "+arg); } // Implement the code here public void operationA1() { }; public void operationA2() { }; } abstract class AbstractProductB{ //public abstract void operationB1(); //public abstract void operationB2(); } class ProductB1 extends AbstractProductB{ ProductB1(String arg){ System.out.println("Hello "+arg); } // Implement the code here } class ProductB2 extends AbstractProductB{ ProductB2(String arg){ System.out.println("Hello "+arg); } // Implement the code here } abstract class AbstractFactory{ abstract AbstractProductA createProductA(); abstract AbstractProductB createProductB(); } class ConcreteFactory1 extends AbstractFactory{ AbstractProductA createProductA(){ return new ProductA1("ProductA1"); } AbstractProductB createProductB(){ return new ProductB1("ProductB1"); } } class ConcreteFactory2 extends AbstractFactory{ AbstractProductA createProductA(){ return new ProductA2("ProductA2"); } AbstractProductB createProductB(){ return new ProductB2("ProductB2"); } } //Factory creator - an indirect way of instantiating the factories class FactoryMaker{ private static AbstractFactory pf=null; static AbstractFactory getFactory(String choice){ if(choice.equals("a")){ pf=new ConcreteFactory1(); }else if(choice.equals("b")){ pf=new ConcreteFactory2(); } return pf; } } // Client public class Client{ public static void main(String args[]){ AbstractFactory pf=FactoryMaker.getFactory("a"); AbstractProductA product=pf.createProductA(); //more function calls on product } } |
Applicability & Examples
We should use the Abstract Factory design pattern when:- the system needs to be independent from the way the products it works with are created.
- the system is or should be configured to work with multiple families of products.
- a family of products is designed to work only all together.
- the creation of a library of products is needed, for which is relevant only the interface, not the implementation, too.
Phone Number Example
The example at the beginning of the article can be extended to addresses, too. The AbstractFactory class will contain methods for creating a new entry in the information manager for a phone number and for an address, methods that produce the abstract products Address and PhoneNumber, which belong to AbstractProduct classes. The AbstractProduct classes will define methods that these products support: for the address get and set methods for the street, city, region and postal code members and for the phone number get and set methods for the number.The ConcreteFactory and ConcreteProduct classes will implement the interfaces defined above and will appear in our example in the form of the USAddressFactory class and the USAddress and USPhoneNumber classes. For each new country that needs to be added to the application, a new set of concrete-type classes will be added. This way we can have the EnglandAddressFactory and the EnglandAddress and EnglandPhoneNumber that are files for English address information.
Pizza Factory Example
Another 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.Look & Feel Example
Look & Feel Abstract Factory is the most common example. For example, a GUI framework should support several look and feel themes, such as Motif and Windows look. Each style defines different looks and behaviors for each type of controls: Buttons and Edit Boxes. In order to avoid the hardociding it for each type of control we define an abstract classLookAndFeel. This calls will instantiate, depending on a configuration parameter in the application one of the concrete factories: WindowsLookAndFeel or MotifLookAndFeel. Each request for a new object will be delegated to the instatiated concrete factory which will return the controls with the specific flavorSpecific 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.
Builder Pattern
Motivation
The more complex an application is the complexity of classes and objects used increases. Complex objects are made of parts produced by other objects that need special care when being built. An application might need a mechanism for building complex objects that is independent from the ones that make up the object. If this is the problem you are being confronted with, you might want to try using the Builder (or Adaptive Builder) design pattern.This pattern allows a client object to construct a complex object by specifying only its type and content, being shielded from the details related to the object�s representation. This way the construction process can be used to create different representations. The logic of this process is isolated form the actual steps used in creating the complex object, so the process can be used again to create a different object form the same set of simple objects as the first one.
Intent
- Defines an instance for creating an object but letting subclasses decide which class to instantiate
- Refers to the newly created object through a common interface
Implementation
The Builder design pattern uses the Factory Builder pattern to decide which concrete class to initiate in order to build the desired type of object, as we will see below in the UML diagram:The participants classes in this pattern are:
- The Builder class specifies an abstract interface for creating parts of a Product object.
- The ConcreteBuilder constructs and puts together parts of the product by implementing the Builder interface. It defines and keeps track of the representation it creates and provides an interface for saving the product.
- The Director class constructs the complex object using the Builder interface.
- The Product represents the complex object that is being built.
The following example discusses the case of a text converting application:
The Client needs to convert a document from RTF format to ASCII format. There for, it calls the method createASCIIText that takes as a parameter the document that will be converted. This method calls the concrete builder, ASCIIConverter, that extends the Builder, TextConverter, and overrides its two methods for converting characters and paragraphs, and also the Director, RTFReader, that parses the document and calls the builder�s methods depending on the type of token encountered. The product, the ASCIIText, is built step by step, by appending converted characters.
//Abstract Builder class abstract class TextConverter{ abstract void convertCharacter(char c); abstract void convertParagraph(); } // Product class ASCIIText{ public void append(char c){ //Implement the code here } } //Concrete Builder class ASCIIConverter extends TextConverter{ ASCIIText asciiTextObj;//resulting product /*converts a character to target representation and appends to the resulting*/ object void convertCharacter(char c){ char asciiChar = new Character(c).charValue(); //gets the ascii character asciiTextObj.append(asciiChar); } void convertParagraph(){} ASCIIText getResult(){ return asciiTextObj; } } //This class abstracts the document object class Document{ static int value; char token; public char getNextToken(){ //Get the next token return token; } } //Director class RTFReader{ private static final char EOF='0'; //Delimitor for End of File final char CHAR='c'; final char PARA='p'; char t; TextConverter builder; RTFReader(TextConverter obj){ builder=obj; } void parseRTF(Document doc){ while ((t=doc.getNextToken())!= EOF){ switch (t){ case CHAR: builder.convertCharacter(t); case PARA: builder.convertParagraph(); } } } } //Client public class Client{ void createASCIIText(Document doc){ ASCIIConverter asciiBuilder = new ASCIIConverter(); RTFReader rtfReader = new RTFReader(asciiBuilder); rtfReader.parseRTF(doc); ASCIIText asciiText = asciiBuilder.getResult(); } public static void main(String args[]){ Client client=new Client(); Document doc=new Document(); client.createASCIIText(doc); system.out.println("This is an example of Builder Pattern"); } } |
Applicability & Examples
Builder Pattern is used when:- the creation algorithm of a complex object is independent from the parts that actually compose the object
- the system needs to allow different representations for the objects that are being built
Example 1 - Vehicle Manufacturer.
Let us take the case of a vehicle manufacturer that, from a set of parts, can build a car, a bicycle, a motorcycle or a scooter. In this case the Builder will become the VehicleBuilder. It specifies the interface for building any of the vehicles in the list above, using the same set of parts and a different set of rules for every type of type of vehicle. The ConcreteBuilders will be the builders attached to each of the objects that are being under construction. The Product is of course the vehicle that is being constructed and the Director is the manufacturer and its shop.Example 1 - Students Exams.
If we have an application that can be used by the students of a University to provide them with the list of their grades for their exams, this application needs to run in different ways depending on the user that is using it, user that has to log in. This means that, for example, the admin needs to have some buttons enabled, buttons that needs to be disabled for the student, the common user. The Builder provides the interface for building form depending on the login information. The ConcreteBuilders are the specific forms for each type of user. The Product is the final form that the application will use in the given case and the Director is the application that, based on the login information, needs a specific form.Specific problems and implementation
Builder and Abstract Factory
The Builder design pattern is very similar, at some extent, to the Abstract Factory pattern. That�s why it is important to be able to make the difference between the situations when one or the other is used. In the case of the Abstract Factory, the client uses the factory�s methods to create its own objects. In the Builder�s case, the Builder class is instructed on how to create the object and then it is asked for it, but the way that the class is put together is up to the Builder class, this detail making the difference between the two patterns.Common interface for productsIn practice the products created by the concrete builders have a structure significantly different, so if there is not a reason to derive different products a common parent class. This also distinguishes the Builder pattern from the Abstract Factory pattern which creates objects derived from a common type.
Prototype Pattern
Motivation
Today’s programming is all about costs. Saving is a big issue when it comes to using computer resources, so programmers are doing their best to find ways of improving the performance When we talk about object creation we can find a better way to have new objects: cloning. To this idea one particular design pattern is related: rather than creation it uses cloning. If the cost of creating a new object is large and creation is resource intensive, we clone the object.The Prototype design pattern is the one in question. It allows an object to create customized objects without knowing their class or any details of how to create them. Up to this point it sounds a lot like the Factory Method pattern, the difference being the fact that for the Factory the palette of prototypical objects never contains more than one object.
Intent
- specifying the kind of objects to create using a prototypical instance
- creating new objects by copying this prototype
- Client - creates a new object by asking a prototype to clone itself.
- Prototype - declares an interface for cloning itself.
- ConcretePrototype - implements the operation for cloning itself. The process of cloning starts with an initialized and instantiated class. The Client asks for a new object of that type and sends the request to the Prototype class. A ConcretePrototype, depending of the type of object is needed, will handle the cloning through the Clone() method, making a new instance of itself. Here is a sample code for the Prototype pattern:
- Classes to be instantiated are specified at run-time
- Avoiding the creation of a factory hierarchy is needed
- It is more convenient to copy an existing instance than to create a new one.
- Prototype Manager – implemented usually as a hashtable keeping the object to clone. When use it, prototype become a factory method which uses cloning instead of instantiation.
- Deep Clones vs. Shallow Clones – when we clone complex objects which contains other objects, we should take care how they are cloned. We can clone contained objects also (deep cloning) or we can the same reference for them, and to share them between cloned container objects.
- Initializing Internal States – there are certain situations when objects need to be initialized after they are created.
Object Pool
Motivation
Performance can be sometimes the key issue during the software development and the object creation(class instantiation) is a costly step. While the Prototype pattern helps in improving the performance by cloning the objects, the Object Pool pattern offer a mechanism to reuse objects that are expensive to create.
Clients of an object pull "feel" like they are owners of a service although the service is shared among many other clients.
Intent
-reuse and share objects that are expensive to create.
Implementation
Implementation involves the following objects:
Reusable - Wraps the limited resource, will be shared by several clients for a limited amount of time.
Client - uses an instance of type Reusable.
ReusablePool - manage the reusable objects for use by Clients, creating and managing a pool of objects.
When a client asks for a Reusable object, the pool performs the following actions:
- Search for an available Reusable object and if it was found it will be returned to the client.
- If no Reusable object was found then it tries to create a new one. If this actions succeds the new Reusable object will be returned to the client.
- If the pool was unable to create a new Reusable, the pool will wait until a reusable object will be released.
The Client is responsible to request the Reusable object as well to release it to the pool. If this action will not be performed the Reusable object will be lost, being considered unavailable by the ResourcePool.
The clients are not aware that they are sharing the Reusable object. From the client poinf of view they are the owners of a new object which comes from the Resource pool in the same way that it comes from a factory or another creational design pattern. The only difference is that the Client should mark the Reusable object as available, after it finishes to use it. It's not about releasing the objects; for example if we work with databases, when a connection is closed it's not necesarely distroyed, it means that it can be reused by another client.
Why to use it?
Basically, we'll use an object pool whenever there are several clients who needs the same stateless resource which is expensive to create.
Applicability & Examples
Lets' take the example of the database connections. It's obviosly that opening too many connections might affect the performance for several reasons:
Creating a connection is an expensive operation.
When there are too many connections opened it takes longer to create a new one and the database server will become overloaded.
Here the object pool comes in to picture to manage the connections and provide a way to reuse and share them. It can also limit the maximum number of objects that can be created.
This pattern provide the following mechaninsm:
Connection - represent the object which is instantiated by the client. From the client perspective this object is instantiated and it handles the database operations and it is the only object visible to the client. The client is not aware that it uses some shared connections. Internally this class does not contain any code for connecting to the database and calls ConnectionPool.aquireImpl to get a ConnectionImpl object and then delegates the request to ConnectionImpl.
ConnectionImpl is the object which implements the database operations which are exposed by Connection for the client.
ConnectionPool is the main actor to manage the connections to the database. It keeps a list of ConnectionImpl objects and instantiates new objects if this is required.
When the client needs to query the database it instantiate a new Connection object specifing the database name and the call the query method which returns a set of records. From the client point of view this is all.
When the Connection.Query methd is called it asks for a ConnectionImpl object from the ConnectionPool. The ConnectionPool tries to find and return an unused object and if it doesn't find it creates one. At this point the maximum number of connections can be limited and if it was reached the pool cand wait until one will be available or return null. In the query method the request is delegated to the ConnectionImpl object returned by the object pool. Since the request is just delegated it's recomended to have the same method signature in Connection and ConnectionImpl.
Specific problems and implementation
Singleton reusable pool - The reusable pool is implemented as a singleton. The reusable pool should be accesible only to the Connection object.
1. Limited number of resources in the pool
The connection pool is responsable for sharing and reusing the resources. Sometimes the resources have to be well managed only because they affects the performace, but there are situations when the number of resources can not exceed a specific limit. In this case the Resource pool check the number of instantiated resources and of the limit is reach it will wait for a resource to be released, it will throw an exception or it will return a null value. In any of the last 2 situations the Client should be notified that the action failed because there are no available resources.
2. Handling situations when creating a new resource fails
There are many reasons when the ResourcePool.acquireConnectionImpl method fails to return a resource. It might happens because there are not available resources or some exception occured. Either way the client should be notified about his.
3. Syncronization
In order to work in a multithreading environment the methods that are used by differnt threads should be synchronized. There are only three methonds in the ResourcePool object that have to be synchronized:
- getInstance should be synchronized or should contain a synchronized block. For details check the singleton multithreading implementation.
- acquireConnectionImpl - this menthod returns a resource and should be synchronized not to return the same resource to two different clients running tin different threads.
- releaseConnectionImpl - this method release a resource. Ussually it doesn't have to be synchronized a resource is allocated only by one client. Internally some blocks might need to be synchronized(depending on the method implementation and the internal structures used to keep the pool.).
4. Expired resources(unused but still reserved)
The main problem for the Object Pool Pattern is that the objects should be released by the client when it finishes using them. There are plenty of examples when the client ”forget” to release the resources. Let's take the example the the database connections when connection are not closed/released after they are used. This seems a minor problem but there are many applications crushing for this reason.
In object pool can be implemented a mechanism to check when a specific resource was used last time and if the time expired, to return it to the available resource pool.
Hot Points
- When the Object Pool pattern is used the objects should be marked as available(released) by the client after they are used, so the pool will be aware about this. This is the main drawback because the client should do this and it's a common situation when database connection are not released afer they are used. To overcome this a mechanism can be implemented to release resources if they are not used for a period of time.
- Creating the resources might fail and this case should be treated carefully. When there is no available resource(beacause the number is limited or creating a new one failed) the client should be notified about it.
Conclusion
Althrough the object pool is handling the object instantiation it's main purpose is to provide a way for the clients to reuse the objects like they are new objects, without being shared and reused.
Behavioral Design Patterns
Chain of Responsibility
Motivation
In writing an application of any kind, it often happens that the event generated by one object needs to be handled by another one. And, to make our work even harder, we also happen to be denied access to the object which needs to handle the event. In this case there are two possibilities: there is the beginner/lazy approach of making everything public, creating reference to every object and continuing from there and then there is the expert approach of using the Chain of Responsibility.
The Chain of Responsibility design pattern allows an object to send a command without knowing what object will receive and handle it. The request is sent from one object to another making them parts of a chain and each object in this chain can handle the command, pass it on or do both. The most usual example of a machine using the Chain of Responsibility is the vending machine coin slot: rather than having a slot for each type of coin, the machine has only one slot for all of them. The dropped coin is routed to the appropriate storage place that is determined by the receiver of the command.
Intent:- It avoids attaching the sender of a request to its receiver, giving this way other objects the possibility of handling the request too.- The objects become parts of a chain and the request is sent from one object to another across the chain until one of the objects will handle it.
ImplementationThe UML diagram of classes below will help us understand better the way the Chain works.
In the diagram above some explanations are needed on what is the role of every class:- Handler - defines an interface for handling requests- RequestHandler:- handles the requests it is responsible for- If it can handle the request it does so, otherwise it sends the request to its successor- Client - sends commands to the first object in the chain that may handle the command
Here is how sending a request works in the application using the Chain of Responsibility: the Client in need of a request to be handled sends it to the chain of handlers, which are classes that extend the Handler class. Each of the handlers in the chain takes its turn at trying to handle the request it receives from the client. If ConcreteHandler_i can handle it, then the request is handled, if not it is sent to the handler ConcreteHandler_i+1, the next one in the chain.
The classic example of the Chain of Responsibility's implementation is presented for us below:
public class Request {private int m_value;private String m_description;public Request(String description, int value){m_description = description;m_value = value;}public int getValue(){return m_value;}public String getDescription(){return m_description;}}
public abstract class Handler{protected Handler m_successor;
public void setSuccessor(Handler successor){m_successor = successor;}public abstract void handleRequest(Request request);}
public class ConcreteHandlerOne extends Handler{public void handleRequest(Request request){if (request.getValue() < 0){ //if request is eligible handle itSystem.out.println("Negative values are handled by ConcreteHandlerOne:");System.out.println("\tConcreteHandlerOne.HandleRequest : " + request.getDescription() + request.getValue());}// if notelsesuper.handleRequest(request);}}
public class ConcreteHandlerThree extends Handler{public void handleRequest(Request request){if (request.getValue() >= 0){ //if request is eligible handle itSystem.out.println("Zero values are handled by ConcreteHandlerThree:");System.out.println("\tConcreteHandlerThree.HandleRequest : " + request.getDescription() + request.getValue());}// if notelsesuper.handleRequest(request);}}public class ConcreteHandlerTwo extends Handler{public void handleRequest(Request request){if (request.getValue() > 0){ //if request is eligible handle itSystem.out.println("Positive values are handled by ConcreteHandlerTwo:");System.out.println("\tConcreteHandlerTwo.HandleRequest : " + request.getDescription() + request.getValue());}// if notelsesuper.handleRequest(request);}}public class Main {
public static void main(String[] args) {// Setup Chain of ResponsibilityHandler h1 = new ConcreteHandlerOne();Handler h2 = new ConcreteHandlerTwo();Handler h3 = new ConcreteHandlerThree();h1.setSuccessor(h2);h2.setSuccessor(h3);// Send requests to the chainh1.handleRequest(new Request("Negative Value ", -1));h1.handleRequest(new Request("Negative Value ", 0));h1.handleRequest(new Request("Negative Value ", 1));h1.handleRequest(new Request("Negative Value ", 2));h1.handleRequest(new Request("Negative Value ", -5));}}
Applicability & ExamplesHaving so many design patterns to choose from when writing an application, it's hard to decide on which one to use, so here are a few situations when using the Chain of Responsibility is more effective:- More than one object can handle a command- The handler is not known in advance- The handler should be determined automatically- It’s wished that the request is addressed to a group of objects without explicitly specifying its receiver- The group of objects that may handle the command must be specified in a dynamic way
Here are some real situations in which the Chain of Responsibility is used:
Example 1
In designing the software for a system that approves the purchasing requests.
In this case, the values of purchase are divided into categories, each having its own approval authority. The approval authority for a given value could change at any time and the system should be flexible enough to handle the situation.The Client in the example above is the system in need of the answer to the approval. It sends a request about it to an purchase approval authority. Depending on the value of the purchase, this authority may approve the request or forward it to the next authority in the chain.For example let’s say a request is placed for the purchase of a new keyboard for an office. The value of the purchase is not that big, so the request is sent from the head of the office to the head of the department and then to the materials department where it stops, being handled locally. But if equipment for the whole department is needed then the request goes form the head of the department, to materials department, to the purchase office and even to the manager if the value is too big.
Example 2
In designing the software that uses a set of GUI classes where it is needed to propagate GUI events from one object to another.
When a event, such as the pressing of a key or the click of the mouse, the event is needed to be sent to the object that has generated it and also to the object or objects that will handle it.The Client is, of course, the object that has generated the event, the request is the event and the handlers are the objects that can handle it. So, if we have a handler for the click of the mouse, a handler for the pressing of the ‘Enter’ key and a handler for the pressing of the ‘Delete’ key, that is the chain of handlers that take care of the events that are generated.
Example 3
In designing a shipping system for electronic orders.
The steps to complete and handle the order differs form one order to another based on the customer, the size of the order, the way of shipment, destination and more other reasons. The business logic changes also as special cases appear, needing the system to be able to handle all cases.The Client, the electronic order in process, requests shipping based on a set of pieces of information. Its request is turned by the system into a specific form, combining the steps to completing and the details of handling, based on the input information. The system will send this type of request through a chain of order-handlers until the input information that it comes with matches the input the order-handles takes. When special cases appear, all that is needed is a new handler to be added in the chain.
Specific problems and implementationThe classic implementation of the Chain of Responsibility is just the first step in applying the pattern to our own application. Improvements based on the type of commands we are handling are needed, in order to make the use of this pattern effective.
- Representing requests
In real life each handler represents a system. And each system can handle specific requests or requests common to more handlers. We should take this issue in consideration when we implement this pattern. In the classical samples of the CoR found on the net you can see that the request is generally represented by an integer. Of course in real life we can not use primary data types as a request.
A clever design should be a flexible one. The best solution here is to create an interface a super class Request (or and interface) where to the default behavior. Then if we need to add a new handler and a specific request all we need is to extend the Request base class.
Of course this is not the only approach. Let’s consider the shipping system example. Each request will have to contain a large amount of data. Creating request examples for this might be difficult. We can take some xml objects containing the data, generated during the application flow (let’s assume we already have the code implemented for that) and pass them to each handler.
Or since the data was already saved in the database (let’s assume that also) we can pass only the id’s of the involved objects and then each handler will take the data required from db.
- Unhandled requests
Unfortunately, the Chain doesn't guarantee that every command is handled, which makes the problem worse, since unhandled commands propagate through the full length of the chain, slowing down the application. One way to solve this is by checking if, at the end of the chain, the request has been handled at least once, otherwise we will have to implement handlers for all the possible requests that may appear.
- Broken Chain
Sometimes we could forget to include in the implementation of the handleRequest method the call to the successor, causing a break in the chain. The request isn’t sent forward from the broken link and so it ends up unhandled. A variation of the pattern can be made to send the request to all the handlers by removing the condition from the handler and always calling the successor.
The following implementation eliminates the Broken Chain problem. The implementation moves the code to traverse the chain into the base class keeping the request handling in a different method in the subclasses. The handleRequest method is declared as final in the base class and is responsible to traverse the chain. Each Handler have to implement the handleRequestImpl method, declared as abstract in the super class.
public abstract class Handler{private Handler m_successor;public void setSuccessor(Handler successor){m_successor = successor;}protected abstract boolean handleRequestImpl(Request request);public final void handleRequest(Request request){boolean handledByThisNode = this.handleRequestImpl(request);if (m_successor != null && !handledByThisNode)m_successor.handleRequest(request);}}
protected boolean handleRequestImpl(Request request){if (request.getValue() < 0){ //if request is eligible handle itSystem.out.println("Negative values are handled by ConcreteHandlerOne:");System.out.println("\tConcreteHandlerOne.HandleRequest : " + request.getDescription() + request.getValue());return true;}// if notelsereturn false;}
The above implementation not only that eliminates the broken chain problem, but it also offers an increased level of flexibility. Only by changing the handleRequest method we can change the pattern to send to al handlers regardless the request handling:
public final void handleRequest(Request request){boolean handledByThisNode = this.handleRequestImpl(request);if (m_successor != null && !handledByThisNode)m_successor.handleRequest(request);}- Avoiding spam requests
For example, an improvement that we could find useful is avoiding sending spam commands. This way, the concrete extension of the HandleRequest function will look like this:
public void HandleRequest(int request) {if(isSpam(request)) { // if the request is spam take spam-related actions}else { // request is not spam.super.HandleRequest(request); // Pass message to next filter in the chain.}}
- Use on existing code
The last, but not least problem that the Chain of Responsibility creates to a programmer is the fact that it is impossible to introduce the pattern into the existing classes without modifying the source code and, even in the case where the pattern is already included in the code, if new operations need to be added to the Handler, it is impossible to do that without modifying the source code. So the basic idea is to decide from the start on whether to use the pattern or not and if we do, what methods we need.
Hot points
- The fundamental flaw of the pattern is the fact that it gets easily broken: if the programmer forgets to call the next handler in the concreteHandler the request gets lost on the way. This problem comes from the fact that the execution is not handled entirely by the superclass and the call is triggered in the superclass.
- When implementing the CoR pattern a special care should be taken for the request representation. The request is not considered a distinctive part of the CoR pattern, but it is still used in all the components of the pattern.
- Another flaw of the Chain of Responsibility is the fact that some requests may end up unhandled due to the wrong implementation of concrete handler, their propagation slowing down the rest of the application. This means that extra care is needed when taking into account the requests that may appear in the process.
Template Method
Motivation
If we take a look at the dictionary definition of a template we can see that a template is a preset format, used as a starting point for a particular application so that the format does not have to be recreated each time it is used.
On the same idea is the template method is based. A template method defines an algorithm in a base class using abstract operations that subclasses override to provide concrete behavior.
Intent
- Define the skeleton of an algorithm in an operation, deferring some steps to subclasses.
- Template Method lets subclasses redefine certain steps of an algorithm without letting them to change the algorithm's structure.
Implementation
AbstractClass - defines abstract primitive operations that concrete subclasses define to implement steps of an algorithm.
- implements a template method which defines the skeleton of an algorithm. The template method calls primitive operations as well as operations defined in AbstractClass or those of other objects.
ConcreteClass - implements the primitive operations to carry out subclass-specific steps of the algorithm.
When a concrete class is called the template method code will be executed from the base class while for each method used inside the template method will be called the implementation from the derived class.
Applicability & Examples
The Template Method pattern should be used:
- to implement the invariant parts of an algorithm once and leave it up to subclasses to implement the behavior that can vary.
- when refactoring is performed and common behavior is identified among classes. A abstract base class containing all the common code (in the template method) should be created to avoid code duplication.
Example - Application used by a travel agency.
Lets' assume we have to develop an application for a travel agency. The travel agency is managing each trip. All the trips contain common behavior but there are several packages. For example each trip contains the basic steps:
- The tourists are transported to the holiday location by plane/train/ships,...
- Each day they are visiting something
- They are returning back home.
So we create an abstract class containing each step as an abstract method and one concrete and final method that calls all the abstracts methods. Then we create one superclass for each package:
public class Trip {
public final void performTrip(){
doComingTransport();
doDayA();
doDayB();
doDayC();
doReturningTransport
}
public abstract void doComingTransport();
public abstract void doDayA();
public abstract void doDayB();
public abstract void doDayC();
public abstract void doReturningTransport();
}
public class PackageA extends Trip {
public void doComingTransport() {
System.out.println("The turists are comming by air ...");
}
public void doDayA() {
System.out.println("The turists are visiting the aquarium ...");
}
public void doDayB() {
System.out.println("The turists are going to the beach ...");
}
public void doDayC() {
System.out.println("The turists are going to mountains ...");
}
public void doReturningTransport() {
System.out.println("The turists are going home by air ...");
}
}
public class PackageB extends Trip {
public void doComingTransport() {
System.out.println("The turists are comming by train ...");
}
public void doDayA() {
System.out.println("The turists are visiting the mountain ...");
}
public void doDayB() {
System.out.println("The turists are going to the beach ...");
}
public void doDayC() {
System.out.println("The turists are going to zoo ...");
}
public void doReturningTransport() {
System.out.println("The turists are going home by train ...");
}
}
Specific problems and implementation
Concrete base class
It is not necessary to have the superclass as a abstract class. It can be a concrete class containing a method (template method) and some default functionality. In this case the primitive methods can not be abstract and this is a flaw because it is not so clear which methods have to be overridden and which not.
A concrete base class should be used only when customizations hooks are implemented.
Template method can not be overridden
The template method implemented by the base class should not be overridden. The specific programming language modifiers should be used to ensure this.
Customization Hooks
A particular case of the template method pattern is represented by the hooks. The hooks are generally empty methods that are called in superclass (and does nothing because are empty), but can be implemented in subclasses. Customization Hooks can be considered a particular case of the template method as well as a totally different mechanism.
Usually a subclass can have a method extended by overriding id and calling the parent method explicitly:
class Subclass extends Superclass
{
...
void something() {
// some customization code to extend functionality
super. something ();
// some customization code to extend functionality
}
}
Unfortunately it is easy to forget to call the super and this is forcing the developer to check the existing code from the method in Superclass.
Instead of overriding some hook methods can be added. Then in the subclasses only the hooks should be implemented without being aware of the method something:
class Superclass
{
...
protected void preSomethingHook(){}
protected void postSomethingHook(){}
void something() {
preSomethingHook();
// something implementation
postSomethingHook();
}
}
class Subclass extends Superclass
{
protected void preSomethingHook()
{
// customization code
}
protected void postSomethingHook()
{
// customization code
}
}
Minimizing primitive methods number
It's important when designing template methods to minimize the number of primitive methods that a subclass must override in order to provide a clear an easy way to implement concrete templates.
Naming Convetions
In order to identify the primitive methods is it better to use a specific naming convention. For example the prefix “do” can be used for primitive methods. In a similar way the customizations hooks can have prefixes like “pre” and “post”.
When methods that should be abstract or not
When there is a method in the base class that should contain default some code, but on the other side it's necessary to be extended in the subclasses it should be split in 2 methods: one abstract and one concrete. We can not rely in the fact that the subclasses will override the method and will call the super implementation in it like this:
void something() {
super. something ();
// extending the method
}
Template Method and Strategy Design Pattern
The strategy pattern is with Template Method pattern. The difference consists in the fact that Strategy uses delegation while the Template Methods uses the inheritance.
Hot points
Template method is using as an inverted controls structure, sometimes referred as “the Hollywood principle”: from the superclass point of view: “Don't call us, we'll call you”. This refers to the fact that instead of calling the methods from base class in the subclasses, the methods from subclass are called in the template method from superclass.
Due to the above fact a special care should be paid to the access modifiers: the template method should be implemented only in the base class, and the primitive method should be implemented in the subclasses. A particular case of the template method is represented by the customization hooks.
Structural Design Patterns:
Adapter Pattern
Motivation
The adapter pattern is adapting between classes and objects. Like any adapter in the real world it is used to be an interface, a bridge between two objects. In real world we have adapters for power supplies, adapters for camera memory cards, and so on. Probably everyone have seen some adapters for memory cards. If you can not plug in the camera memory in your laptop you can use and adapter. You plug the camera memory in the adapter and the adapter in to laptop slot. That's it, it's really simple.
What about software development? It's the same. Can you imagine an situation when you have some class expecting some type of object and you have an object offering the same features, but exposing a different interface? Of course, you want to use both of them so you don't to implement again one of them, and you don't want to change existing classes, so why not create an adapter...
Intent
- Convert the interface of a class into another interface clients expect.
- Adapter lets classes work together, that could not otherwise because of incompatible interfaces.
Implementation
The figure below shows a UML class diagram for the Adapter Pattern:
The classes/objects participating in adapter pattern:
- Target - defines the domain-specific interface that Client uses.
- Adapter - adapts the interface Adaptee to the Target interface.
- Adaptee - defines an existing interface that needs adapting.
- Client - collaborates with objects conforming to the Target interface.
Applicability & Examples
The visitor pattern is used when:
- When you have a class(Target) that invokes methods defined in an interface and you have a another class(Adapter) that doesn't implement the interface but implements the operations that should be invoked from the first class through the interface. You can change none of the existing code. The adapter will implement the interface and will be the bridge between the 2 classes.
- When you write a class (Target) for a generic use relying on some general interfaces and you have some implemented classes, not implementing the interface, that needs to be invoked by the Target class.
- Non Software Examples of Adapter Patterns : Power Supply Adapters, card readers and adapters, ... Software Examples of Adapter Patterns: Wrappers used to adopt 3rd parties libraries and frameworks - most of the applications using third party libraries use adapters as a middle layer between the application and the 3rd party library to decouple the application from the library. If another library has to be used only an adapter for the new library is required without having to change the application code.
Specific problems and implementation
Objects Adapters - Based on Delegation
Objects Adapters are the classical example of the adapter pattern. It uses composition, the Adaptee delegates the calls to Adaptee (opossed to class adapters which extends the Adaptee). This behaviour gives us a few advantages over the class adapters(however the class adapters can be implemented in languages allowing multiple inheritance). The main advantage is that the Adapter adapts not only the Adpatee but all its subclasses. All it's subclasses with one "small" restriction: all the subclasses which don't add new methods, because the used mechanism is delegation. So for any new method the Adapter must be changed or extended to expose the new methods as well. The main disadvantage is that it requires to write all the code for delegating all the necessary requests tot the Adaptee.
Class Adapters - Based on (Multiple) Inheritance
Class adapters can be implemented in languages supporting multiple inheritance(Java, C# or PHP does not support multiple inheritance). Thus, such adapters can not be easy implemented in Java, C# or VB.NET. Class adapter uses inheritance instead of composition. It means that instead of delegating the calls to the Adaptee, it subclasses it. In conclusion it must subclass both the Target and the Adaptee. There are advantages and disadvantages:
- It adapts the specific Adaptee class. The class it extends. If that one is subclassed it can not be adapted by the existing adapter.
- It doesn't require all the code required for delegation, which must be written for an Object Adapter.
How Much the Adapter Should Do?
This question has a really simple response: it should do how much it has to in order to adapt. It's very simple, if the Target and Adaptee are similar then the adapter has just to delegate the requests from the Target to the Adaptee. If Target and Adaptee are not similar, then the adapter might have to convert the data structures between those and to implement the operations required by the Target but not implemented by the Adaptee.
Two-Ways Adapters
The Two-Ways Adapters are adapters that implements both interfaces of Target and Adaptee. The adapted object can be used as Target in new systems dealing with Target classes or as Adaptee in other systems dealing with Adaptee classes. Going further on this line of thinking, we can have adapters implementing n interfaces, adapting to n systems. Two-way adapters and n-way adapters are hard to implement in systems not supporting multiple inheritance. If adapter has to extend the Target class it can not extent another class like Adaptee, so the Adaptee should be an interface and all the calls should be delegated from the adapter to the Adaptee object.
Adapter Pattern and Strategy Pattern
Adapter Pattern and Strategy Pattern - there are many cases when the adapter can play the role of the Strategy Pattern. If we have several modules implementing the same functionality and we wrote adapters for them, the adapters are implementing the same interface. We can simply replace the adapters objects at run time because they implements the same interface.
Flyweight Pattern
Motivation
Some programs require a large number of objects that have some shared state among them. Consider for example a game of war, were there is a large number of soldier objects; a soldier object maintain the graphical representation of a soldier, soldier behavior such as motion, and firing weapons, in addition soldier�s health and location on the war terrain. Creating a large number of soldier objects is a necessity however it would incur a huge memory cost. Note that although the representation and behavior of a soldier is the same their health and location can vary greatly.
Intent
- The intent of this pattern is to use sharing to support a large number of objects that have part of their internal state in common where the other part of state can vary.
Implementation
The figure below shows a UML class diagram for the Flyweight Pattern:
- Flyweight - Declares an interface through which flyweights can receive and act on extrinsic state.
- ConcreteFlyweight - Implements the Flyweight interface and stores intrinsic state. A ConcreteFlyweight object must be sharable. The Concrete flyweight object must maintain state that it is intrinsic to it, and must be able to manipulate state that is extrinsic. In the war game example graphical representation is an intrinsic state, where location and health states are extrinsic. Soldier moves, the motion behavior manipulates the external state (location) to create a new location.
- FlyweightFactory - The factory creates and manages flyweight objects. In addition the factory ensures sharing of the flyweight objects. The factory maintains a pool of different flyweight objects and returns an object from the pool if it is already created, adds one to the pool and returns it in case it is new.
In the war example a Soldier Flyweight factory can create two types of flyweights : a Soldier flyweight, as well as a Colonel Flyweight. When the Client asks the Factory for a soldier, the factory checks to see if there is a soldier in the pool, if there is, it is returned to the client, if there is no soldier in pool, a soldier is created, added to pool, and returned to the client, the next time a client asks for a soldier, the soldier created previously is returned, no new soldier is created. - Client - A client maintains references to flyweights in addition to computing and maintaining extrinsic state
Applicability & Examples
The flyweight pattern applies to a program using a huge number of objects that have part of their internal state in common where the other part of state can vary. The pattern is used when the larger part of the object�s state can be made extrinsic (external to that object).
Example - The war game.
The war game instantiates 5 Soldier clients, each client maintains its internal state which is extrinsic to the soldier flyweight. And Although 5 clients have been instantiated only one flyweight Soldier has been used.
Specific problems and implementation
Text Editors
Object oriented text editors need to create Character Objects to represent each character that is in the document. A Character object maintains information about what is the character, what is its font, what is the size of the character, as well as character location inside the document. A document typically consists of extremely large number of character objects which requires large memory. Note that the number of characters in general (Digits, Letters, Other special characters) is known and is fixed, and the fonts that can be applied to each character are also known, thus by creating a Letter flyweight that maintains Character Type (letter, digit, etc�), as well as font, and by creating a Letter Client object that only maintains each character�s location inside the document, we have reduced the editor�s memory requirements drastically.
Consequences
Flyweight pattern saves memory by sharing flyweight objects among clients. The amount of memory saved generally depends on the number of flyweight categories saved (for example a soldier category and a lieutenant category as discussed earlier).
Related Patterns
Factory and Singleton patterns - Flyweights are usually created using a factory and the singleton is applied to that factory so that for each type or category of flyweights a single instance is returned.
State and Strategy Patterns - State and Strategy objects are usually implemented as Flyweights.
Known Uses
Games with graphics as discussed with the War Game Example
Text Editors as discussed in the Text Editors example.
Decorator Pattern
Motivation
Extending an object�s functionality can be done statically (at compile time) by using inheritance however it might be necessary to extend an object�s functionality dynamically (at runtime) as an object is used.
Consider the typical example of a graphical window. To extend the functionality of the graphical window for example by adding a frame to the window, would require extending the window class to create a FramedWindow class. To create a framed window it is necessary to create an object of the FramedWindow class. However it would be impossible to start with a plain window and to extend its functionality at runtime to become a framed window.
Intent
- The intent of this pattern is to add additional responsibilities dynamically to an object.
Implementation
The figure below shows a UML class diagram for the Decorator Pattern:
The participants classes in the decorator pattern are:
- Component - Interface for objects that can have responsibilities added to them dynamically.
- ConcreteComponent - Defines an object to which additional responsibilities can be added.
- Decorator - Maintains a reference to a Component object and defines an interface that conforms to Component's interface.
- Concrete Decorators - Concrete Decorators extend the functionality of the component by adding state or adding behavior.
Description
The decorator pattern applies when there is a need to dynamically add as well as remove responsibilities to a class, and when subclassing would be impossible due to the large number of subclasses that could result.
Applicability & Examples
Example - Extending capabilities of a Graphical Window at runtime
In Graphical User Interface toolkits windows behaviors can be added dynamically by using the decorator design pattern.
Specific problems and implementation
Graphical User Interface Frameworks
GUI toolkits use decoration pattern to add functionalities dynamically as explained before.
Related Patterns
- Adapter Pattern - A decorator is different from an adapter in that a decorator changes object's responsibilities, while an adapter changes an object interface.
- Composite Pattern - A decorator can be viewed as a degenerate composite with only one component. However, a decorator adds additional responsibilities.
Consequences
- Decoration is more convenient for adding functionalities to objects instead of entire classes at runtime. With decoration it is also possible to remove the added functionalities dynamically.
- Decoration adds functionality to objects at runtime which would make debugging system functionality harder.
Known Uses:
- GUI toolkits as has been previously explained.
Composite Pattern
Motivation
There are times when a program needs to manipulate a tree data structure and it is necessary to treat both Branches as well as Leaf Nodes uniformly. Consider for example a program that manipulates a file system. A file system is a tree structure that contains Branches which are Folders as well as Leaf nodes which are Files. Note that a folder object usually contains one or more file or folder objects and thus is a complex object where a file is a simple object. Note also that since files and folders have many operations and attributes in common, such as moving and copying a file or a folder, listing file or folder attributes such as file name and size, it would be easier and more convenient to treat both file and folder objects uniformly by defining a File System Resource Interface.
Intent
- The intent of this pattern is to compose objects into tree structures to represent part-whole hierarchies.
- Composite lets clients treat individual objects and compositions of objects uniformly.
Implementation
The figure below shows a UML class diagram for the Composite Pattern:
- Component - Component is the abstraction for leafs and composites. It defines the interface that must be implemented by the objects in the composition. For example a file system resource defines move, copy, rename, and getSize methods for files and folders.
- Leaf - Leafs are objects that have no children. They implement services described by the Component interface. For example a file object implements move, copy, rename, as well as getSize methods which are related to the Component interface.
- Composite - A Composite stores child components in addition to implementing methods defined by the component interface. Composites implement methods defined in the Component interface by delegating to child components. In addition composites provide additional methods for adding, removing, as well as getting components.
- Client - The client manipulates objects in the hierarchy using the component interface.
Applicability & Examples
The composite pattern applies when there is a part-whole hierarchy of objects and a client needs to deal with objects uniformly regardless of the fact that an object might be a leaf or a branch.
Example - Graphics Drawing Editor.
In graphics editors a shape can be basic or complex. An example of a simple shape is a line, where a complex shape is a rectangle which is made of four line objects. Since shapes have many operations in common such as rendering the shape to screen, and since shapes follow a part-whole hierarchy, composite pattern can be used to enable the program to deal with all shapes uniformly.
In the example we can see the following actors:
- Shape (Component) - Shape is the abstraction for Lines, Rectangles (leafs) and and ComplexShapes (composites).
- Line, Rectangle (Leafs) - objects that have no children. They implement services described by the Shape interface.
- ComplexShape (Composite) - A Composite stores child Shapes in addition to implementing methods defined by the Shape interface.
- GraphicsEditor (Client) - The GraphicsEditor manipulates Shapes in the hierarchy.
Specific problems and implementation
Graphics Editors use composite pattern to implement complex and simple graphics as previously explained.
File System implementations use the composite design pattern as described previously.
Consequences
- The composite pattern defines class hierarchies consisting of primitive objects and composite objects. Primitive objects can be composed into more complex objects, which in turn can be composed.
- Clients treat primitive and composite objects uniformly through a component interface which makes client code simple.
- Adding new components can be easy and client code does not need to be changed since client deals with the new components through the component interface.
Related Patterns
Decorator Pattern - Decorator is often used with Composite. When decorators and composites are used together, they will usually have a common parent class. So decorators will have to support the Component interface with operations like Add, Remove, and GetChild.
Known Uses
File System Implementation as discussed previously.
Graphics Editors as discussed previously.
Bridge Pattern
Motivation
Sometimes an abstraction should have different implementations; consider an object that handles persistence of objects over different platforms using either relational databases or file system structures (files and folders). A simple implementation might choose to extend the object itself to implement the functionality for both file system and RDBMS. However this implementation would create a problem; Inheritance binds an implementation to the abstraction and thus it would be difficult to modify, extend, and reuse abstraction and implementation independently.
Intent
- The intent of this pattern is to decouple abstraction from implementation so that the two can vary independently.
Implementation
The figure below shows a UML class diagram for the Bridge Pattern:
The participants classes in the bridge pattern are:
- Abstraction - Abstraction defines abstraction interface.
- AbstractionImpl - Implements the abstraction interface using a reference to an object of type Implementor.
- Implementor - Implementor defines the interface for implementation classes. This interface does not need to correspond directly to abstraction interface and can be very different. Abstraction imp provides an implementation in terms of operations provided by Implementor interface.
- ConcreteImplementor1, ConcreteImplementor2 - Implements the Implementor interface.
Description
An Abstraction can be implemented by an abstraction implementation, and this implementation does not depend on any concrete implementers of the Implementor interface. Extending the abstraction does not affect the Implementor. Also extending the Implementor has no effect on the Abstraction.
Applicability & Examples
The bridge pattern applies when there is a need to avoid permanent binding between an abstraction and an implementation and when the abstraction and implementation need to vary independently. Using the bridge pattern would leave the client code unchanged with no need to recompile the code.
Example - Object Persistence API Example
As discussed previously a persistence API can have many implementations depending on the presence or absence of a relational database, a file system, as well as on the underlying operating system.
Specific problems and implementation
Graphical User Interface Frameworks
Graphical User Interface Frameworks use the bridge pattern to separate abstractions from platform specific implementation. For example GUI frameworks separate a Window abstraction from a Window implementation for Linux or Mac OS using the bridge pattern.
Related Patterns
- Abstract Factory Pattern - An Abstract Factory pattern can be used create and configure a particular Bridge, for example a factory can choose the suitable concrete implementor at runtime.
Consequences
Known Uses:
- Decoupling interface and implementation. An implementation is not bound permanently to an interface. The implementation of an abstraction can be configured and even switched at run-time.
- Abstraction and Implementor hierarchies can be extended independently.
Known Uses:
- GUI frameworks as discussed previously.
- Persistence Frameworks as discussed previously.
Proxy Pattern
Motivation
Sometimes we need the ability to control the access to an object. For example if we need to use only a few methods of some costly objects we'll initialize those objects when we need them entirely. Until that point we can use some light objects exposing the same interface as the heavy objects. These light objects are called proxies and they will instantiate those heavy objects when they are really need and by then we'll use some light objects instead.
This ability to control the access to an object can be required for a variety of reasons: controlling when a costly object needs to be instantiated and initialized, giving different access rights to an object, as well as providing a sophisticated means of accessing and referencing objects running in other processes, on other machines.
Consider for example an image viewer program. An image viewer program must be able to list and display high resolution photo objects that are in a folder, but how often do someone open a folder and view all the images inside. Sometimes you will be looking for a particular photo, sometimes you will only want to see an image name. The image viewer must be able to list all photo objects, but the photo objects must not be loaded into memory until they are required to be rendered.
Intent
- The intent of this pattern is to provide a �Placeholder� for an object to control references to it.
Implementation
The figure below shows a UML class diagram for the Proxy Pattern:
The participants classes in the proxy pattern are:
- Subject - Interface implemented by the RealSubject and representing its services. The interface must be implemented by the proxy as well so that the proxy can be used in any location where the RealSubject can be used.
- Proxy
- Maintains a reference that allows the Proxy to access the RealSubject.
- Implements the same interface implemented by the RealSubject so that the Proxy can be substituted for the RealSubject.
- Controls access to the RealSubject and may be responsible for its creation and deletion.
- Other responsibilities depend on the kind of proxy.
- RealSubject - the real object that the proxy represents.
Description
A client obtains a reference to a Proxy, the client then handles the proxy in the same way it handles RealSubject and thus invoking the method doSomething(). At that point the proxy can do different things prior to invoking RealSubject�s doSomething() method. The client might create a RealSubject object at that point, perform initialization, check permissions of the client to invoke the method, and then invoke the method on the object. The client can also do additional tasks after invoking the doSomething() method, such as incrementing the number of references to the object.
Applicability & Examples
The Proxy design pattern is applicable when there is a need to control access to an Object, as well as when there is a need for a sophisticated reference to an Object. Common Situations where the proxy pattern is applicable are:
- Virtual Proxies: delaying the creation and initialization of expensive objects until needed, where the objects are created on demand (For example creating the RealSubject object only when the doSomething method is invoked).
- Remote Proxies: providing a local representation for an object that is in a different address space. A common example is Java RMI stub objects. The stub object acts as a proxy where invoking methods on the stub would cause the stub to communicate and invoke methods on a remote object (called skeleton) found on a different machine.
- Protection Proxies: where a proxy controls access to RealSubject methods, by giving access to some objects while denying access to others.
- Smart References: providing a sophisticated access to certain objects such as tracking the number of references to an object and denying access if a certain number is reached, as well as loading an object from database into memory on demand.
Example - Virtual Proxy Example.
Consider an image viewer program that lists and displays high resolution photos. The program has to show a list of all photos however it does not need to display the actual photo until the user selects an image item from a list.
The code below shows the Image interface representing the Subject. The interface has a single method showImage() that the Concrete Images must implement to render an image to screen.
package proxy; /** * Subject Interface */ public interface Image { public void showImage(); }
The code below shows the Proxy implementation, the image proxy is a virtual proxy that creates and loads the actual image object on demand, thus saving the cost of loading an image into memory until it needs to be rendered:
package proxy; /** * Proxy */ public class ImageProxy implements Image { /** * Private Proxy data */ private String imageFilePath; /** * Reference to RealSubject */ private Image proxifiedImage; public ImageProxy(String imageFilePath) { this.imageFilePath= imageFilePath; } @Override public void showImage() { // create the Image Object only when the image is required to be shown proxifiedImage = new HighResolutionImage(imageFilePath); // now call showImage on realSubject proxifiedImage.showImage(); } }
The code below displays the RealSubject Implementation, which is the concrete and heavyweight implementation of the image interface. The High resolution image, loads a high resolution image from disk, and renders it to screen when showImage() is called.
package proxy; /** * RealSubject */ public class HighResolutionImage implements Image { public HighResolutionImage(String imageFilePath) { loadImage(imageFilePath); } private void loadImage(String imageFilePath) { // load Image from disk into memory // this is heavy and costly operation } @Override public void showImage() { // Actual Image rendering logic } }
The code below illustrates a sample image viewer program; the program simply loads three images, and renders only one image, once using the proxy pattern, and another time directly. Note that when using the proxy pattern, although three images have been loaded, the High resolution image is not loaded into memory until it needs to be rendered, while in the part not using the proxy, the three images are loaded into memory although one of them is actually rendered.
package proxy; /** * Image Viewer program */ public class ImageViewer { public static void main(String[] args) { // assuming that the user selects a folder that has 3 images //create the 3 images Image highResolutionImage1 = new ImageProxy("sample/veryHighResPhoto1.jpeg"); Image highResolutionImage2 = new ImageProxy("sample/veryHighResPhoto2.jpeg"); Image highResolutionImage3 = new ImageProxy("sample/veryHighResPhoto3.jpeg"); // assume that the user clicks on Image one item in a list // this would cause the program to call showImage() for that image only // note that in this case only image one was loaded into memory highResolutionImage1.showImage(); // consider using the high resolution image object directly Image highResolutionImageNoProxy1 = new HighResolutionImage("sample/veryHighResPhoto1.jpeg"); Image highResolutionImageNoProxy2 = new HighResolutionImage("sample/veryHighResPhoto2.jpeg"); Image highResolutionImageBoProxy3 = new HighResolutionImage("sample/veryHighResPhoto3.jpeg"); // assume that the user selects image two item from images list highResolutionImageNoProxy2.showImage(); // note that in this case all images have been loaded into memory // and not all have been actually displayed // this is a waste of memory resources } }
Specific problems and implementation
Java Remote Method Invocation (RMI)
In java RMI an object on one machine (executing in one JVM) called a client can invoke methods on an object in another machine (another JVM) the second object is called a remote object. The proxy (also called a stub) resides on the client machine and the client invokes the proxy in as if it is invoking the object itself (remember that the proxy implements the same interface that RealSubject implements). The proxy itself will handle communication to the remote object, invoke the method on that remote object, and would return the result if any to the client. The proxy in this case is a Remote proxy.
Related Patterns
- Adapter Design Pattern - The adapter implements a different interface to the object it adapts where a proxy implements the same interface as its subject.
- Decorator Design Pattern - A decorator implementation can be the same as the proxy however a decorator adds responsibilities to an object while a proxy controls access to it.
Consequences
Known Uses:
- Java RMI as has been explained implements a remote proxy
- Security Proxies that controls access to objects can be found in many object oriented languages including java, C#, C++.
Implementation
The pattern uses abstract classes, as we will see below and only three types of classes making its implementation rather easy. The classes participating to the Prototype Pattern are:public interface Prototype { public abstract Object clone ( ); } public class ConcretePrototype implements Prototype { public Object clone() { return super.clone(); } } public class Client { public static void main( String arg[] ) { ConcretePrototype obj1= new ConcretePrototype (); ConcretePrototype obj2 = ConcretePrototype)obj1.clone(); } } |
// Violation of Likov's Substitution Principle class Rectangle { protected int m_width; protected int m_height; public void setWidth(int width){ m_width = width; } public void setHeight(int height){ m_height = height; } public int getWidth(){ return m_width; } public int getHeight(){ return m_height; } public int getArea(){ return m_width * m_height; } } class Square extends Rectangle { public void setWidth(int width){ m_width = width; m_height = width; } public void setHeight(int height){ m_width = height; m_height = height; } } class LspTest { private static Rectangle getNewRectangle() { // it can be an object returned by some factory ... return new Square(); } public static void main (String args[]) { Rectangle r = LspTest.getNewRectangle(); r.setWidth(5); r.setHeight(10); // user knows that r it's a rectangle. // It assumes that he's able to set the width and height as for the base class System.out.println(r.getArea()); // now he's surprised to see that the area is 100 instead of 50. } } |
No comments:
Post a Comment