Design Patterns
Creational Design Patterns:
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:
The participants classes in this pattern are:
· Product defines the interface for objects the factory method creates.
· ConcreteProduct implements the Product interface.
· Creator(also refered as Factory because it creates the Product objects) declares the method FactoryMethod, which returns a Product object. May call the generating method for creating Product objects
· ConcreteCreator overrides the generating method for creating ConcreteProduct objects
All concrete products are subclasses of the Product class, so all of them have the same basic implementation, at some extent. The Creator class specifies all standard and generic behavior of the products and when a new product is needed, it sends the creation details that are supplied by the client to the ConcreteCreator. Having this diagram in mind, it is easy for us now to produce the code related to it. Here is how the implementation of the classic Factory method should look:
public interface Product { … }
public abstract class Creator { public void anOperation() { Product product = factoryMethod(); } protected abstract Product factoryMethod(); }
public class ConcreteProduct implements Product { … }
public class ConcreteCreator extends Creator { protected Product factoryMethod() { return new ConcreteProduct(); } }
public class Client { public static void main( String arg[] ) { Creator creator = new ConcreteCreator(); creator.anOperation(); } } |
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 (); } |
Assuming that the Application class has a member called docs that represents a list of documents being handled by the application, then the NewDocument method should look like this:
public void NewDocument(String type){ Document doc=CreateDocument(type); Docs.add(doc); Doc.Open(); } |
This method will be inherited by the MyApplication class and, so, through the CreateDocument method, it will actually instantiate MyDocument objects. We will call the CreateDocument method a Factory Method because it is responsible with 'making' an object. Through this method, redefined in Application's subclasses, we can actually shape the situation in which the Application class creates objects without knowing their type. From this point of view the factory method is pattern which provides us a way to achieve the DIP principle.
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.
Factory method is just a particular case of the factory design pattern. In the same time it is the most known factory pattern, maybe because it was published in the GoF. In modern programming languages the factory with registration is more used.
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(); |
Factory Method pattern should be used when:
- a framework delegate the creation of objects derived from a common superclass to the factory
- the base factory class does not know what concrete classes will be required to create - delegates to its subclasses the creation of concrete objects
- factory subclasses subclasses are aware of the concrete classes that must be instantiated
Factory method pattern, compared to Factory pattern replace the factory with an abstract class and a set of concrete factories subclasses. The subclasses are responsible for creating concrete product objects; for factory method is possible adding new product classes without changing the abstract factory. The same result can be achieved for simplified factory pattern if reflection is used.
- a framework delegate the creation of objects derived from a common superclass to the factory
- the base factory class does not know what concrete classes will be required to create - delegates to its subclasses the creation of concrete objects
- factory subclasses subclasses are aware of the concrete classes that must be instantiated
Factory method pattern, compared to Factory pattern replace the factory with an abstract class and a set of concrete factories subclasses. The subclasses are responsible for creating concrete product objects; for factory method is possible adding new product classes without changing the abstract factory. The same result can be achieved for simplified factory pattern if reflection is used.
Along with singleton pattern the factories are the most used patterns. Almost any application has some factories. Here are a some examples:
- factories providing an xml parser: javax.xml.parsers.DocumentBuilderFactory or javax.xml.parsers.SAXParserFactory
- factories providing an xml parser: javax.xml.parsers.DocumentBuilderFactory or javax.xml.parsers.SAXParserFactory
Abstract FactoryMotivationModularization 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. ImplementationThe 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 AbstractFactory class is the one that determines the actual type of the concrete object and creates it, but it returns an abstract pointer to the concrete object just created. This determines the behavior of the client that asks the factory to create an object of a certain abstract type and to return the abstract pointer to it, keeping the client from knowing anything about the actual creation of the object. The fact that the factory returns an abstract pointer to the created object means that the client doesn't have knowledge of the object's type. This implies that there is no need for including any class declarations relating to the concrete type, the client dealing at all times with the abstract type. The objects of the concrete type, created by the factory, are accessed by the client only through the abstract interface. The second implication of this way of creating objects is that when the adding new concrete types is needed, all we have to do is modify the client code and make it use a different factory, which is far easier than instantiating a new type, which requires changing the code wherever a new object is created. The classic implementation for the Abstract Factory pattern is the following:
Applicability & ExamplesWe 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 ExampleThe 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 ExampleAnother 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 ExampleLook & 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 class LookAndFeel. 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 flavor Specific problems and implementationThe 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 singletonsAn 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 productsThe 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 factoriesThe 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. |
Abstract Factory should be used when:
· A system should be configured with one of multiple families of products
· A system should be independent of how its products are created, composed and represented
· Products from the same family should be used all together, products from different families ahould not be used togheter and this constraint must be ensured.
· Only the product interfaces are revealed, the implementations remains hidden to the clients.
Examples of abstract factories:
· java.awt.Toolkit - the abstract superclass of all actual implementations of the Abstract Window Toolkit. Subclasses of Toolkit are used to bind the various components to particular native toolkit implementations(Java AWT).
· javax.swing.LookAndFeel - an abstract swing factory to swithct between several look and feel for the components displayed(Java Swing).
· java.sql.Connection - an abstract factory which create Statements, PreparedStatements, CallableStatements,... for each database flavor.
Builder PatternMotivationThe 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 ImplementationThe 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 client, that may be either another object or the actual client that calls the main() method of the application, initiates the Builder and Director class. The Builder represents the complex object that needs to be built in terms of simpler objects and types. The constructor in the Director class receives a Builder object as a parameter from the Client and is responsible for calling the appropriate methods of the Builder class. In order to provide the Client with an interface for all concrete Builders, the Builder class should be an abstract one. This way you can add new types of complex objects by only defining the structure and reusing the logic for the actual construction process. The Client is the only one that needs to know about the new types, the Director needing to know which methods of the Builder to call. 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.
Applicability & ExamplesBuilder 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 implementationBuilder and Abstract FactoryThe 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 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 and creating new objects by copying this prototype Implementation The pattern uses abstract classes, as we will see below and only three types of classes making its implementation rather easy. 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: 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(); } } This example is rather trivial, but the real use of the pattern comes when we don’t know what we’re actually cloning. For example if we need the newly created object to be stored in a hashtable we can use it like this: dataStore.put(obj1); Applicability & Examples Use Prototype Pattern when a system should be independent of how its products are created, composed, and represented, and - 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 Example 1: In building stages for a game that uses a maze and different visual objects that the character encounters it is needed a quick method of generating the haze map using the same objects: wall, door, passage, room... The Prototype pattern is useful in this case because instead of hard coding (using new operation) the room, door, passage and wall objects that get instantiated, CreateMaze method will be parameterized by various prototypical room, door, wall and passage objects, so the composition of the map can be easily changed by replacing the prototypical objects with different ones. The Client is the CreateMaze method and the ConcretePrototype classes will be the ones creating copies for different objects. Example 2: Suppose we are doing a sales analysis on a set of data from a database. Normally, we would copy the information from the database, encapsulate it into an object and do the analysis. But if another analysis is needed on the same set of data, reading the database again and creating a new object is not the best idea. If we are using the Prototype pattern then the object used in the first analysis will be cloned and used for the other analysis. The Client is here one of the methods that process an object that encapsulates information from the database. The ConcretePrototype classes will be classes that, from the object created after extracting data from the database, will copy it into objects used for analysis. Specific problems and implementation Using a prototype manager When the application uses a lot of prototypes that can be created and destroyed dynamically, a registry of available prototypes should be kept. This registry is called the prototype manager and it should implement operations for managing registered prototypes like registering a prototype under a certain key, searching for a prototype with a given key, removing one from the register, etc. The clients will use the interface of the prototype manager to handle prototypes at run-time and will ask for permission before using the Clone() method. There is no much difference between an implementation of a prototype which uses a prototype manager and a factory method implemented using class registration mechanism. Maybe the only difference consists in the performance. Implementing the Clone operation A small discussion appears when talking about how deep or shallow a clone should be: a deep clone clones the instance variables in the cloning object while a shallow clone shares the instance variables between the clone and the original. Usually, a shallow clone is enough and very simple, but cloning complex prototypes should use deep clones so the clone and the original are independent, a deep clone needing its components to be the clones of the complex object’s components. Initializing clones There are cases when the internal states of a clone should be initialized after it is created. This happens because these values cannot be passed to the Clone() method, that uses an interface which would be destroyed if such parameters were used. In this case the initialization should be done by using setting and resetting operations of the prototype class or by using an initializing method that takes as parameters the values at which the clone’s internal states should be set. Hot points - 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. Basically, we'll use an object pool whenever there are several clients who needs the same stateless resource which is expensive to create. The most common situations when object pool pattern is used: - Database Connections - Remote Objects |
No comments:
Post a Comment