CSC/ECE 517 Fall 2011/ch4 4h as: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
Line 237: Line 237:


==Strategy Pattern==
==Strategy Pattern==
=== Formal Definition ===
''Strategy pattern is a pattern which encapsulates a defined family of algorithms and thus makes them interchangeable. Thus, Strategy pattern allows the Client to change algorithms according to his will. Execution of the Algorithm will take place through a crystallized and common interface.''
Let’s take a real world example to understand this pattern much better. Consider a Program where you have to sort a list of numbers. Note that the list of numbers is the data which is common to all algorithms here. If we were to write a program with one class consisting of all the algorithms as functions like BubbleSort, QuickSort, SelectionSort etc., the class would become too hard and huge to handle. The Program would consist of a central if-else OR switch case which would use different algorithms according to the Client input. Now, if we need to add another algorithm into this program, we have to add another function and add another else-if condition OR a switch case which is too tedious and dangerous. If we make one mistake in writing this code, we might end up with a broken program.
Strategy Pattern aims at eliminating this problem by defining classes encapsulating different sorting algorithms and then let the Client/user use a common interface to set and call different algorithms at will.
=== Common Applications ===
The strategy pattern should be used when:
*We have different versions of an algorithm to be used in our program.
*We have a class which displays different behavior – or a class which has to be configured to display different behaviors.
*We have a class which consists of different operations which are inefficiently expressed as multiple if-else statements or switch cases.
*We have an algorithm which is to be implemented in such a say that the user should know nothing about it. Thus, algorithm should be encapsulated from the user.
=== Participants ===
==Conclusion==
==Conclusion==
==References==
==References==

Revision as of 02:43, 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

Command Pattern
Figure 1. Working of the Command Pattern.

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.

Implementation Example

For the implementation Example, lets take a look at how we can implement the Homework function in the example mentioned at the beginning of the pattern explanation.

public class Homework {
	public void doHomework(){
		System.out.println("Homework is done.");
	}
}
public interface Command {
	public void execute();
}
public class HomeworkCommand implements Command {
	Homework homework;
	public setHomework(Homework homework){
		this.homework = homework;
	}
	
	public void execute(){
		homework.doHomework();
	}
}
public class Invoker {
	Command command;  			     // Command is referenced by the common interface.
	public void setCommand(Command command){
		this.command = command;
	}
	
	public void performAction(){
		command.execute();
	}
}
public class Client {
	public static void main(String args[]){
		Homework homework;
		Invoker invoker;
		HomeworkCommand hwCommand = new HomeworkCommand();
		hwCommand.setHomework(homework);	           //Set the Receiver
		invoker.setCommand(hwCommand);                     // Set Command to Homework. Any other commands can be used.
		invoker.performAction();		           // Will execute Homework's execute.
	}
}

Command Pattern in Ruby

Command Pattern in Ruby can be accomplished by using Procs. Procs are procedures which consist of binding of variables in its scope when it is created. When we call any Proc, it is not necessary for the caller to know the internal details of the Proc or how it is implemented. The caller just has to pass the required arguments and get the output. This ensures the decoupling of the caller from the method.

Procs make is easy to implement the Command Pattern efficiently in Ruby.

Strategy Pattern

Formal Definition

Strategy pattern is a pattern which encapsulates a defined family of algorithms and thus makes them interchangeable. Thus, Strategy pattern allows the Client to change algorithms according to his will. Execution of the Algorithm will take place through a crystallized and common interface.

Let’s take a real world example to understand this pattern much better. Consider a Program where you have to sort a list of numbers. Note that the list of numbers is the data which is common to all algorithms here. If we were to write a program with one class consisting of all the algorithms as functions like BubbleSort, QuickSort, SelectionSort etc., the class would become too hard and huge to handle. The Program would consist of a central if-else OR switch case which would use different algorithms according to the Client input. Now, if we need to add another algorithm into this program, we have to add another function and add another else-if condition OR a switch case which is too tedious and dangerous. If we make one mistake in writing this code, we might end up with a broken program.

Strategy Pattern aims at eliminating this problem by defining classes encapsulating different sorting algorithms and then let the Client/user use a common interface to set and call different algorithms at will.

Common Applications

The strategy pattern should be used when:

  • We have different versions of an algorithm to be used in our program.
  • We have a class which displays different behavior – or a class which has to be configured to display different behaviors.
  • We have a class which consists of different operations which are inefficiently expressed as multiple if-else statements or switch cases.
  • We have an algorithm which is to be implemented in such a say that the user should know nothing about it. Thus, algorithm should be encapsulated from the user.

Participants

Conclusion

References