Showing posts with label strategy pattern. Show all posts
Showing posts with label strategy pattern. Show all posts

Tuesday, 19 April 2011

Restricted Access Containers (RACs) and the Strategy Pattern

Introduction

Stacks and queues are examples of containers with special insertion and removal behaviors and a special access behavior.

Stack
Insertion and removal in a stack must be carried out in such a way that the last data inserted is the first one to be removed.   One can only retrieve and remove a data element from a stack by way of special access point called the "top".   Traditionally, the insertion and removal methods for a stack are called push and pop, respectively.  push inserts a data element at the top of the stack.  pop removes and returns the data element at the top of the stack.  A stack is used to model systems that exhibit LIFO (Last In First Out) insert/removal behavior.

Queue
Data insertion and removal in a queue must be carried out in such a way that  the first one to be inserted is the first one to be removed.   One can only retrieve and remove a data element from a queue by way of special access point called the "front".  Traditionally, the insertion and removal methods for a queue are called enqueue and dequeue, respectively.  enqueue inserts a data element at the "end" of the queue.  dequeue removes and returns the data element at the front of the queue.  A queue is used to model systems that exhibit FIFO  (First In First Out) insertion/removal behavior.  For example, one can model a movie ticket line by a queue.

We abstract the behaviors of special containers such as stacks and queues into an interface called IRAContainer specified as follows. 

Restricted Access Containers 

package genRac;
import genListFW.*;
/**
* Defines the interface for a restricted access container.
*/

public interface IRAContainer<T> {
/**
* Empty the container.
* NOTE: This implies a state change.
* This behavior can be achieved by repeatedly removing elements from this IRAContainer.
* It is specified here as a convenience to the client.
*/

public void clear();

/**
* Return TRUE if the container is empty; otherwise, return
* FALSE.
* Question: do we really need this method?
*/

public boolean isEmpty();

/**
* Return TRUE if the container is full; otherwise, return
* FALSE.
*/

public boolean isFull();

/**
* Return an immutable list of all elements in the container.
* @param fact for manufacturing an IList.
*/

public IList<T> elements(IListFactory<T> fact);


/**
* Remove the next item from the container and return it.
* NOTE: This implies a state change.
* @throw an Exception if this IRAContainer is empty.
*/

public T get();

/**
* Add an item to the container.
* NOTE: This implies a state change.
* @param input the data to be added to this IRAContainer.
* @throw an Exception if this IRAContainer is full.
*/

public void put(T input);

/**
* Return the next element in this IRAContainer withour removing it.
* @throw an Exception if this IRAContainer is empty.
*/

public T peek();
}
  1. Restrict the users from seeing inside or working on the inside of the container.
  2. Have simple put(data) and get() methods. Note the lack of specification of how the data goes in or comes out of the container.
  3. However, a "policy" must exist that governs how data is added ("put") or removed ("get"). Examples:
    1. First in/First out (FIFO) ("Queue")
    2. Last in/First out (LIFO) ("Stack")
    3. Retrieve by ranking ("Priority Queue")
    4. Random retrieval
  4. The policy is variant behavior --> abstract it.
    1. The behavior of the RAC is independent of exactly what the policy does.
    2. The RAC delegates the actual adding ("put") work to the policy.
    3. The RAC is only dependent on the existence of the policy, not what it does.
    4. The policy is a "strategy" for adding data to the RAC. See the Strategy design pattern.
    5. Strategy pattern vs. State pattern -- so alike, yet so different!(here for difference)
The manufacturing of specific restricted access containers with specific insertion strategy will be done by concrete implementations of the following abstract factory interface.

IRACFactory.java
package genRac;
/**
* Abstract Factory to manufacture RACs.
*/

public interface IRACFactory<T> {
/**
* Returns an empty IRAContainer.
*/

public IRAContainer<T> makeRAC();
}
 

Examples

The following is an (abstract) implementation of IRACFactory using the generic LRStruct as the underlining data structure.  By varying the insertion strategy, which is an IAlgo on the internal LRStruct, we obtain different types of RAC: stack, queue, random, etc. 
NOTE: Due to the limitation of our UML tool, the UML class diagram shown below does not show the generic type of all the classes.


ALRSRACFactory.java
package genRac;
import genListFW.*;import genListFW.factory.*;import genLRS.*;
/**
* Implements a factory for restricted access containers. These
* restricted access containers are implemented using an generic LRStruct to
* hold the data objects.
* Click here for the public methods of the generic LRStruct and visitor.
*/

public abstract class ALRSRACFactory<T> implements IRACFactory<T> {

/**
* Implements a general-purpose restricted access container using
* a generic LRStruct. How?
*
* The next item to remove is always at the front of the list of
* contained objects. This is invariant!
*
* Insertion is, however, delegated to a strategy routine; and
* this strategy is provided to the container. This strategy
* varies to implement the desired kind of container, e.g., queue
* vs. stack.
*
* This nested static class is protected so that classes derived from its
* factory can reuse it to create other kinds of restricted access
* container.
*/

protected static class LRSRAContainer<T> implements IRAContainer<T> {
private IAlgo<T, Object, T> _insertStrategy;
private LRStruct<T> _lrs;

// anonymous inner class to check for emptiness!
private IAlgo<Object, Boolean, Object> _checkEmpty = new IAlgo<Object, Boolean, Object>() {

public Boolean emptyCase(LRStruct<? extends Object> host, Object... input) {
return Boolean.TRUE;
}

public Boolean nonEmptyCase(LRStruct<? extends Object> host, Object... input) {
return Boolean.FALSE;
}
};

public LRSRAContainer(IAlgo<T, Object, T> strategy) {
_insertStrategy = strategy;
_lrs =
new LRStruct<T>();
}

/**
* Empty the container.
*/

public void clear() {
_lrs =
new LRStruct<T>();
}

/**
* Return TRUE if the container is empty; otherwise, return
* FALSE.
*/

public boolean isEmpty() {
return _lrs.execute(_checkEmpty);
}

/**
* Return TRUE if the container is full; otherwise, return
* FALSE.
*
* This implementation can hold an arbitrary number of
* objects. Thus, always return false.
*/

public boolean isFull() {
return false;
}

/**
* Return an immutable list of all elements in the container.
*/

public IList<T> elements(final IListFactory<T> fact) {

return _lrs.execute (new IAlgo<T, IList<T>, Object>() {

public IList<T> emptyCase(LRStruct<? extends T> host, Object... nu) {
return fact.makeEmptyList();
}

public IList<T> nonEmptyCase(LRStruct<? extends T> host, Object... nu) {
return fact.makeNEList(host.getFirst(),
host.getRest().execute(
this));
}
});
}

/**
* Remove the next item from the container and return it.
*/

public T get() {
return _lrs.removeFront();
}

/**
* Add an item to the container.
*/

public void put(T input) {
_lrs.execute(_insertStrategy, input);
}

public T peek() {
return _lrs.getFirst();
}
}
}
 
LRSStackFactory.java
package genRac;
import genLRS.*;
public class LRSStackFactory<T> extends ALRSRACFactory<T> {
/**
* Create a ``last-in, first-out'' (LIFO) container.
*/

public IRAContainer<T> makeRAC() {

return new LRSRAContainer<T> (new IAlgo<T, Object, T>() {

public Object emptyCase(LRStruct<? extends T> host, T... input) {
return ((LRStruct<T>)host).insertFront(input[0]);
}

public Object nonEmptyCase(LRStruct<? extends T> host, T... input) {
return ((LRStruct<T>)host).insertFront(input[0]);
}
});
}
}

LRSQueueFactory.java
package genRac;
import genLRS.*;
public class LRSQueueFactory<T> extends ALRSRACFactory<T> {

/**
* Create a ``first-in, first-out'' (FIFO) container.
*/

public IRAContainer<T> makeRAC() {

return new LRSRAContainer<T> (new IAlgo<T, Object, T>() {

public Object emptyCase(LRStruct<? extends T> host, T... input) {
return ((LRStruct<T>)host).insertFront(input[0]);
}

public Object nonEmptyCase(LRStruct<? extends T> host, T... input) {
return ((LRStruct<T>)host).getRest().execute(this, input[0]);
}
});
}
}
RandomRACFactory.java
package genRac;
import genLRS.*;
/*
* Implements a factory for restricted access containers, including a
* container that returns a random item.
*/

public class RandomRACFactory<T> extends ALRSRACFactory<T> {
/**
* Create a container that returns a random item.
*/

public IRAContainer<T> makeRAC() {

return new LRSRAContainer<T> (new IAlgo<T, Object, T>() {

public Object emptyCase(LRStruct<? extends T> host, T... input) {
return ((LRStruct<T>)host).insertFront(input[0]);
}

public Object nonEmptyCase(LRStruct<? extends T> host, T... input) {
/*
* Math.Random returns a value between 0.0 and 1.0.
*/

if (0.75 > Math.random())
return ((LRStruct<T>)host).insertFront(input[0]);
else
return ((LRStruct<T>)host).getRest().execute(this, input[0]);
}
});
}
}

 





Wednesday, 2 March 2011

Strategy vs State Design Patterns.

1. State: Encapsulate interchangable behaviours and use delegation to decide which behaviour to use.
Strategy: Subclasses decide how to implement steps in an algorithm.
2. With State Pattern we have a set of behaviours encapsulated in state objects; at any time the context is delegating to one of those states. Over time, the current state changes across the set of state objecs to reflect the internal state of context, so the context's behaviour changes over time as well. The client usually knows very little, if anything about the state objects.
With Strategy, the client usually specifies the strategy object that the context is composed with. Now, while the pattern provides the flexibility to change the strategy object at runtime, often there is a strategy object that is most appropriate for a context object.
3. Think of the State Pattern as an alternative to putting lots of conditionals in your context; by encapsulating the behaviours within state objects, you can simply change the state object in context to change its behaviour.

State Design Pattern

The State Pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class
What does it mean for an object to "appear to change its class?" Think about it from the perspective of a client: if an object you are using can completely change its behavior, then it appears to you that the object is actually instantiated from another class. In reality, however you know that we are using composition to give the appearance of a class change by simply referencing different state objects.
Motivation
  • State charts are often used to describe dynamic behavior
  • The "traditional" way to implement state transitions often involves complicated, nested if statements
      For example the behaviour of an object Room's isDark() is different when the values of property light changes.
public boolean isDark()
{
if(swichLight().equalsIgnoreCase("off"))
return true;
else
return false;
}


Let us look at detailed example:
Consider the life of a person, it has 4 states - childhood, boyhood, youth and old-age. So
now if you are youth, you do something different and when you are boy you do different.
So the logic uses nested ifs to find what the state is and then perform logic.
//With out using StateDesign Pattern



public class Life
{
final static int CHILD = 0;
final static int BOY = 1;
final static int YOUTH = 2;
final static int OLD = 3;

int state = CHILD;

public void children(){
if(state == CHILD){
System.out.println("Go and Play...");
state = BOY;
}
else if(state == BOY)
System.out.println("Don't behave like a kid");
else if(state == YOUTH)
System.out.println("Don't behave like a kid");
else if(state == OLD)
System.out.println("Don't behave like a kid");
}

public void schoolBoy(){
if(state == CHILD)
System.out.println("grow up...");
else if(state == BOY){
System.out.println("Its time to go to school");
state = YOUTH;
}
else if(state == YOUTH)
System.out.println("Don't behave like a boy");
else if(state == OLD)
System.out.println("Don't behave like a boy");
}

public void youngGeneration(){
if(state == CHILD)
System.out.println("grow up...");
else if(state == BOY)
System.out.println("grow up...");
else if(state == YOUTH){
System.out.println("Right time to achieve my goals...");
state = OLD;
}
else if(state == OLD)
System.out.println("You are no longer youth");
}

public void oldGeneration(){
if(state == CHILD)
System.out.println("grow up...");
else if(state == BOY)
System.out.println("grow up...");
else if(state == YOUTH){
System.out.println("grow up...");
state = OLD;
}
else if(state == OLD)
System.out.println("I can guide you all");
}

public String toString(){
return state+"";
}

// Other methods...
}

The State Pattern
  • Delegate the responsibility of handling state transitions to encapsulations of the states
  • Participants:
    • An abstract State  
    • Several concrete State classes
    • A Context
By encapsulating each state into a class, we localize any changes that will need to be made.
State transitions can be controlled by State Classes or by Context Classes.

Objects are often discussed in terms of having a "state" that describes their exact conditions in a given time, based upon the values of their properties. The particular values of the properties affect the object's behavior.

Now if we use State Design Pattern here, we can get rid of this messy if else code in Life Class and also make it flexible.

//With State Design Pattern


public interface State{
public void childhood();
public void boyhood();
public void youth();
public void old();
}




public class ChildHoodState implements State{

Life life;

public ChildHoodState(Life life){
this.life = life;
}

public void childhood(){
System.out.println("Go and Play...");
life.setState(life.boyHoodState);
}
public void boyhood(){
System.out.println("Don't behave like a kid");
}
public void youth(){
System.out.println("Don't behave like a kid");
}
public void old(){
System.out.println("Don't behave like a kid");
}
}




public class BoyHoodState implements State{

Life life;

public BoyHoodState(Life life){
this.life = life;
}

public void childhood(){
System.out.println("Grow up.. ");
}
public void boyhood(){
System.out.println("Its time to go to school");
life.setState(life.youthState);
}
public void youth(){
System.out.println("Don't behave like a boy");
}
public void old(){
System.out.println("Don't behave like a boy");
}
}




public class YouthState implements State{

Life life;

public YouthState(Life life){
this.life = life;
}

public void childhood(){
System.out.println("Grow up...");
}
public void boyhood(){
System.out.println("Grow up...");
}
public void youth(){
System.out.println("Right time to achieve my goals...");
life.setState(life.oldState);
}
public void old(){
System.out.println("You are no longer youth");
}
}




public class OldState implements State{

Life life;

public OldState(Life life){
this.life = life;
}

public void childhood(){
System.out.println("Grow up...");
}
public void boyhood(){
System.out.println("Grow up...");
}
public void youth(){
System.out.println("Grow up...");
}
public void old(){
System.out.println("I can guide you all");
}
}




public class Life{
// All the States
State childHoodState;
State boyHoodState;
State youthState;
State oldState;

// initialise them
State state = childHoodState;

public Life(){
childHoodState = new ChildHoodState(this);
boyHoodState = new BoyHoodState(this);
youthState = new YouthState(this);
oldState = new OldState(this);
}

// Delegate to current state

public void children(){
state.childhood();
}

public void schoolBoy(){
state.boyhood();
}

public void youngGeneration(){
state.youth();
}

public void oldGeneration(){
state.old();
}

// for transition of state
public void setState(State state){
this.state = state;
}

// Many other methods needed... including getters and setters of each State

}




public class TestLife{
public static void main(String[] args) {
Life life = new Life();
System.out.println(life);

life.children();
life.schoolBoy();
life.youngGeneration();
life.oldGeneration();

System.out.println(life);


}
}


What we are doing here is implementing the behaviours that are appropriate for the state we are in. In some cases this behaviour includes moving the Life forward to new state.
We will have similar kind of classes for 'YouthState' and 'OldState' also ...
From the above explanation we came to know that State Design Pattern is a fully encapsulated, self-modifying Strategy Design Pattern.

Advantage and Disadvantage

In general think of strategy pattern as a flexible alternative to subclassing; if you use inheritence to define the behaviour of a subclass then you are stuck with that behaviour even if you need to change it. With Strategy you can change the behaviour by composing with a different object.
Disadvantage: By encapsulating state behaviour into seperate classes, you'll always end up with more classes in your design. That's often the price you pay for flexibility.