CSC/ECE 517 Fall 2011/ch4 4h as: Difference between revisions
Line 134: | Line 134: | ||
==Command Pattern== | ==Command Pattern== | ||
=== Formal definition === | === Formal definition === | ||
The Command Pattern encapsulates a request as an object and thereby allows us to parameterize other objects with different requests, queue or log requests and support undoable operations. | ''The Command Pattern encapsulates a request as an object and thereby allows us to parameterize other objects with different requests, queue or log requests and support undoable operations.'' | ||
Command Pattern focuses on one important aim: To ensure that the object calling a method is completely unaware of how the method is called, implemented and handled. In other words, it aims at achieving decoupling of the caller and the function being called. | Command Pattern focuses on one important aim: To ensure that the object calling a method is completely unaware of how the method is called, implemented and handled. In other words, it aims at achieving decoupling of the caller and the function being called. |
Revision as of 02:33, 21 October 2011
Introduction
Software Design Patterns
Singleton Pattern
In software engineering the singleton pattern is a creational pattern which is used to ensure that not more than one object is ever created for a class. The singleton also provides a point of global access.
Common Applications
There may be various reasons that necessitate such a requirement for a class.The class may represent the global state of the system or the class may correspond to a master logger which writes into the log file. Some other places where the singleton pattern is applicable are device drivers, registry settings, etc.
Implementation
There are many ways of implementing the singleton pattern. The most common way is to have a method which creates an instance of the object if it does not already exist. Otherwise the existing reference is returned. To make sure that multiple instances are not created the constructor is made private. Also the object which stores the single instance is made a class variable and is thus not tied to any particular instance of the class.
public class Singleton { private static Singleton singletonInstance; private Singleton() { } public static Singleton getInstance() { if (singletonInstance == null) { singletonInstance = new Singleton(); } return singletonInstance; } }
This is an example of lazy instantiation where the object is not created until the first time it is required. Though the above implementation is straight forward, it does not work in a multi threaded environment. If two threads call the getInstance method at the same time, race conditions may result in more than one instance of the class being created, violating the singleton pattern. This problem can be easily solved by making the 'getInstance' method mutually exclusive using locks. In JAVA this is easily achieved by making the 'getInstance' method synchronized.
Alternatively we could replace
private static Singleton singletonInstance;
with
private static Singleton singletonInstance = new Singleton();
This is an example of eager instantiation and it has a pitfall of wasting memory space if the Singleton object never ends up being used. However it should also be noted that this version is thread safe because the singletonInstance is created as soon as the Singleton class is loaded by the class loader.
The above examples present a very common way of implementing the singleton pattern. This is by means an exhaustive list of possible implementations. There are additional methods of achieving the same result such as “double checked locking” and using enum data-type
Adapter Pattern
The adapter pattern, also called wrapper pattern, is used to enable two classes with incompatible interfaces to work together without modifying either class. Adapters are common in real world objects, the most common example being electrical socket adapters which enable electrical appliances from one country to work in another country.
Types
There are two types of adapters
- Object adapters - The adapter described in the example is a object adapter. This uses composition to adapt one class to another.
- Class adapters -This type of adapter requires multiple inheritance and works by subclassing both the interfaces.
Common Applications
The adapter pattern is mostly used to adapt to changing third party vendor libraries. Suppose a system works with an external vendor library and suppose we change vendors and the new vendor library implements a different interface. Now the client class expects a different interface and hence it becomes incompatible with the vendor library. We do not want to rewrite the client code and we cannot change the vendor library. The adapter pattern is ideally suited to solve this problem.
Implementation
Before describing anything let us establish some common terminology here.The vendor class is called adpatee, the class which performs the work of the middleman is called the adapter and the interface implemented by the client is called the target interface.
The adapter is realized using a class which implements the target interface and has a reference to the adaptee. The implementation translates functional calls made against the target interface into calls made against the interface implemented by the adaptee.
The adapter decouples the client from the vendor interface. If the vendor changes a new adapter can be written to accommodate this change.
The following is an Java version of the Square peg round hole example presented in class.
public interface RoundObject { public float getRadius(); } //Round hole expects the object It test for in the fits function to implement the //RoundObject Interface public class RoundHole implements RoundObject { private float radius; public RoundHole(float radius){ this.radius = radius; } @Override public float getRadius(){ return radius; } public boolean fits(RoundObject peg){ return peg.getRadius() <= radius; } }
public interface SquareObject { public float getWidth(); } //Square peg implements SquareObject which is incompatible with RoundObject //Hence RoundHole cannot test if the SquarePeg object fits directly public class SquarePeg implements SquareObject{ private float width; public SquarePeg(float width){ this.width = width; } @Override public float getWidth(){ return width; } }
//The adapter adapts the SquarePeg object so that it is compatible with the //RoundObject Interface. The adapter implements RoundObject Interface and also has a reference to the SqurePeg Object. public class SquarePegAdapter implements RoundObject { private SquarePeg squarePeg; public SquarePegAdapter(SquarePeg squarePeg){ this.squarePeg = squarePeg; } public float getRadius(){ return (float) Math.sqrt(Math.pow(squarePeg.getWidth()/2,2)*2); } } //Hence this test works public class AdapterTest { public static void main(String[] args) { RoundObject adapter = new SquarePegAdapter(new SquarePeg(100)); RoundHole hole = new RoundHole(10); if(hole.fits(adapter)){ System.out.println("Square peg fits into round hole"); } else{ System.out.println("Square peg does not fit into round hole"); } } }
Command Pattern
Formal definition
The Command Pattern encapsulates a request as an object and thereby allows us to parameterize other objects with different requests, queue or log requests and support undoable operations.
Command Pattern focuses on one important aim: To ensure that the object calling a method is completely unaware of how the method is called, implemented and handled. In other words, it aims at achieving decoupling of the caller and the function being called.
Let us consider a real world example to better understand this pattern. Suppose we have a magical drop-box which has the note “Drop and it will be done”. We will be really happy to just drop of errands like ‘Do my Homework’, ‘Pick up my Laundry’ and many more! The point to consider here is that we are calling an unknown function by dropping errands – unknown to us in terms of implementation details – but with a common crystallized interface – The Drop Box! We as invokers are not concerned about how our homework is done or how our laundry is picked up as long it is done and picked up. We are just concerned to drop off our requests into the Box and let it do the rest.
This is precisely what Command Pattern achieves. Now the sections below will explain how exactly the pattern goes about achieving this aim.
Participants
Command
This is an interface which provides the common function (execute) to the Invoker. Thus, the invoker knows that it can carry out the required action using this execute function. This is the interface where additional operations can be declared so that they are available to the invoker. This is the crystallized interface that was mentioned in the above example.
Invoker
Invoker holds the Command object and when required calls the execute operation of the Command to fulfill the required request.
Receiver
Receiver is the enlightened one and knows the actual logic of carrying out the required function/request. The receiver is the one who will receive the request through the execute function invoked by the invoker. Any class can act as a receiver.
CommandObject
The CommandObject is the one which implements the execute function of the Command interface. The CommandObject or ConcreteCommand binds the execute function and the action of the Receiver to be invoked. Thus, this object is the one who actually calls the required action(s) of the Receiver.
Client
Client creates the required CommandObject and sets its Receiver. Thus, the Client will decide as to which Command will actually be executed. The point to note here is that different commands can have different CommandObjects.
Implementation
The above diagram gives a gist of how the command pattern works. Here is what happens.
1. The Client creates the CommandObject which contains the execute function from the Command interface. The CommandObject provides a specific implementation to the execute function in such a way that it binds a set of receiver actions to the execute function in this CommandObject. This execute can be used to invoke the encapsulated actions of the receiver at any time.
2. The Client further invokes the set-Command method which passes the CommandObject to the Invoker as an argument thereby saving the CommandObject reference within the Invoker. Thus, the CommandObject is now stored in the Invoker for any further use. This Object can be used by the Invoker to call the actions on the Receiver whenever the Client asks for it.
3. Now, the Client decides to ask the Invoker to execute the command. Note that the command can stay in the Invoker as long as required and as long as it is not replaced by a different command. Thus, it can be kept or discarded at any point of time.
4. The Invoker calls the CommandObject’s execute method. Note that the invoker only knows about the execute method at this point of time and nothing else. This ensures decoupling between the invoker object and the receiver object.
5. Once the invoker calls execute, the execute function in the CommandObject is executed which in turn contains encapsulated methods of the Receiver Object. These methods are called and the operation is completed. Note here that the CommandObject should hold a reference to the Receiver class for it to actually have the ability to call Receiver’s functions. This setting is controlled and done by the Client.