Sunday, September 7, 2014

Behavioral patterns in Java - Part 1

From wikipedia:
In software engineeringbehavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication.
Examples of this type of design pattern include:
  • Chain of responsibility pattern: Command objects are handled or passed on to other objects by logic-containing processing objects
  • Command pattern: Command objects encapsulate an action and its parameters
  • "Externalize the Stack": Turn a recursive function into an iterative one that uses a stack[1]
  • Interpreter pattern: Implement a specialized computer language to rapidly solve a specific set of problems
  • Iterator pattern: Iterators are used to access the elements of an aggregate object sequentially without exposing its underlying representation
  • Mediator pattern: Provides a unified interface to a set of interfaces in a subsystem
  • Memento pattern: Provides the ability to restore an object to its previous state (rollback)

1. Chain of responsibility

Actors: list (chain) of command objects. Command can have link to "next"(in chain) command.  

Goal: each command tries to do some action and switch execution process to next command.

Main class:


public class ChainOfResponsibility {
    
    public abstract class AbstractCommand {
        public abstract String executeInternal();
        
        AbstractCommand next;
        String name;
        
        public void setName(String name) {
            this.name=name;
        }
        
        public void setNext(AbstractCommand next) {
            this.next=next;
        }
                
        
        public String execute(String commands) {
            String result="";
            if (commands.indexOf(name)>-1) {
                result=executeInternal();
            }           
            if (next!=null) {
                result=result+"."+next.execute(commands);
            }
            return result;
        }
        
    }

    public class CreateCommand extends AbstractCommand {

        @Override
        public String executeInternal() {
            return "create";
        }       
        
    }   
    
    public class DrawCommand extends AbstractCommand {

        @Override
        public String executeInternal() {
            return "draw";
        }       
        
    }
    
    public class MoveCommand extends AbstractCommand {

        @Override
        public String executeInternal() {
            return "move";
        }       
        
    }
    
    public class Client {
        public String execute(String commands) {
            
            CreateCommand createCommand=new CreateCommand();
            createCommand.setName("create");
            
            DrawCommand drawCommand=new DrawCommand();
            drawCommand.setName("draw");
            
            MoveCommand moveCommand=new MoveCommand();
            moveCommand.setName("move");
            
            createCommand.setNext(drawCommand);
            drawCommand.setNext(moveCommand);
            
            return createCommand.execute(commands);
        }
    }
    

}

Test class:

public class ChainOfResponsibilityTest {

    @Test
    public void test() {
        ChainOfResponsibility chainOfResponsibility=new ChainOfResponsibility();
        ChainOfResponsibility.Client client=chainOfResponsibility. new Client();
        
        String result=client.execute("move, create");
        assertEquals("create..move", result);
        
    }

}

2. Command

  Actors: 
  1. executor- interface which have to be implemented by "command" object
  2. command - implementation of executor interface 
  3. receiver - "helper" object which used by command object
  Goal: implementation of "handler": in Java we can not pass function as parameter to another function, but be can pass command object and execute such a function on it.

Main class:




public class Command {

    public interface Executor {
        String execute();
    }
    
    public class Receiver {
        public String draw() {
            return "draw";
        }
        public String erase() {
            return "erase";
        }
    }
    
    public abstract class AbstractCommand implements Executor {
        protected Receiver receiver=new Receiver();
    } 
    
    public class DrawCommand extends AbstractCommand {
        
        @Override
        public String execute() {
            return receiver.draw();
        }
        
    }
    public class EraseCommand extends AbstractCommand {

        @Override
        public String execute() {
            return receiver.erase();
        }       
    }
    
    public class Client {
        public String doSomeAction(List<Executor> commands) {
            StringBuilder result=new StringBuilder();
            
            for (Executor eachCommand:commands) {
                result.append(eachCommand.execute()+".");
            }
            
            return result.toString();
        }
    }
    
}

Test class:

public class CommandTest {

    @Test
    public void test() {
        Command command =new Command();
        Command.DrawCommand draw=command. new DrawCommand();
        Command.EraseCommand erase=command. new EraseCommand();
        
        List<Command.Executor> commandList=new ArrayList<Command.Executor>();
        commandList.add(draw);
        commandList.add(draw);
        commandList.add(erase);
        
        Command.Client client=command. new Client();
        assertEquals("draw.draw.erase.", client.doSomeAction(commandList));
        
        
    }

}

3. Interpretator

Actors:
1. custom command language
2. expression written on this language
3. interpretator class which can interpret expression oin proper way and calculate it
Goal: calculating expression

Main class:
           

public class Interpretator {
    
    interface Operator {
        int calculate(int argument1, int argument2);
    }
    
    class PlusOperator implements Operator {
        
        @Override
        public int calculate(int argument1, int argument2) {            
            return argument1+argument2;
        }
        
    }
    
    class MinusOperator implements Operator {
        
        @Override
        public int calculate(int argument1, int argument2) {            
            return argument1-argument2;
        }
        
    }
    
    class Context {
        
        Map<String, Operator> operatorMap;
        
        public Context(Map<String, Operator> operatorMap) {
            if (operatorMap==null) {
                throw new RuntimeException("OperatorMap can not be null.");
            }
            this.operatorMap=operatorMap;   
        }
        
        
        public int getNearestOperatorPosition(String expression, int position) {
            int result=-1;
            for (String operator:operatorMap.keySet()) {
                int currentOperatorPosition=expression.indexOf(operator, position);
                if (result==-1 || (currentOperatorPosition!=-1 && currentOperatorPosition<result) ) { 
                    result=currentOperatorPosition;         
                }
            }
            return result;
        }
        
        public int getNearestOperandEnd(String expression, int position) {
            int operandEnd=-1;
            int nextOperatorPosition=getNearestOperatorPosition(expression, position);
            if (nextOperatorPosition==-1){
                operandEnd=expression.length();
            } else {
                operandEnd=nextOperatorPosition;
            }
            return operandEnd;
        }
        
        public int calculate(String expression) {
            if (expression==null || expression.length()==0) {
                return 0;
            }
                    
            int position=getNearestOperandEnd(expression, 0);
            String operandStringValue=expression.substring(0, position);
            int result=Integer.parseInt(operandStringValue);
            //position++;
            while (position<expression.length()) {
                String operator=expression.substring(position, position+1);
                Operator e=operatorMap.get(operator);               
                position++;
                int operandEnd=getNearestOperandEnd(expression, position);
                operandStringValue=expression.substring(position, operandEnd);
                int operand=Integer.parseInt(operandStringValue);
                result=e.calculate(result, operand);
                position=operandEnd;
            }
            
            return result;
        }
    }

}

Test class:

public class InterpretatorTest {
    
    Interpretator interpretator=new Interpretator();
    Interpretator.PlusOperator plusOperator=interpretator. new PlusOperator();
    Interpretator.MinusOperator minusOperator=interpretator. new MinusOperator();
    Interpretator.Context context;
    
    @Before
    public void init() {
        Map<String, Operator> operatorMap=new HashMap<String, Operator>();
        operatorMap.put("+", plusOperator);
        operatorMap.put("-", minusOperator);
        context=interpretator. new Context(operatorMap);
    }

    @Test
    public void getNearestOperatorPositionTest() {
        String expression="0123+34";
        int result=context.getNearestOperatorPosition(expression, 0);
        assertEquals(4, result);
        expression="012345-34";
        result=context.getNearestOperatorPosition(expression, 0);
        assertEquals(6, result);
    }
    
    @Test
    public void getNearestOperandEndTest() {
        String expression="0123+56";
        int result=context.getNearestOperandEnd(expression, 0);
        assertEquals(4, result);
        expression="0123+56";
        result=context.getNearestOperandEnd(expression, 5);
        assertEquals(7, result);
    }   
    
    @Test
    public void mainTestWithTraditionalOperators() {
            
        String expression="0123+56+8";
        int result=context.calculate(expression);
        assertEquals(123+56+8, result);
        
        expression="12+34-56";
        result=context.calculate(expression);
        assertEquals(12+34-56, result);
    }
    
    @Test
    public void mainTestWithExperimentalOperators() {
        Map<String, Operator> operatorMap=new HashMap<String, Operator>();
        operatorMap.put("P", plusOperator);
        operatorMap.put("M", minusOperator);
        context=interpretator. new Context(operatorMap);
        
        
        String expression="2P3M1";
        int result=context.calculate(expression);
        assertEquals(4, result);
        
    }   

}

4. Iterator

Actors:
   1. iterator interface which describes it operation list
   2. iterator object which implements interface
   3. iterable object - object which has method for returning it iterator
Goal: iterate through  array of elements using iterator object

Main class:

public class Iterator {

    interface SimpleIterator<T> {
        boolean hasNext();
        T getNext();
    } 
        
    class ArrayIterator<T> implements SimpleIterator<T> {
        T[] array;
        int position=-1;
        
        public ArrayIterator(T[] array) {
            this.array=array;
        }

        @Override
        public boolean hasNext() {
            if (position<array.length-1) {
                return true;
            }
            return false;
        }

        @Override
        public T getNext() {
            position++;
            return array[position];         
        }
        
    }
    
    interface Iterable<T>{
        SimpleIterator<T> getIterator();
    }
    
    class ArrayIterable<T> implements Iterable<T> {
        private T[] array;
        
        public ArrayIterable(T[] array) {
            this.array=array;
        }

        @Override
        public SimpleIterator<T> getIterator() {
            return new ArrayIterator<T>(array);
        }       
    }
        
    
}

Test class:

public class IteratorTest {

    @Test
    public void test() {
        String[] array=new String[]{"a", "b", "c"};
        Iterator iterator=new Iterator();
        Iterator.ArrayIterable<String> arrayIterable=iterator. new ArrayIterable<String>(array);
        Iterator.SimpleIterator<String> arrayIterator=arrayIterable.getIterator();
        StringBuilder result=new StringBuilder();
        while (arrayIterator.hasNext()) {
            String element=arrayIterator.getNext();
            result.append(element);
        }       
        assertEquals("abc", result.toString());             
        
    }

}

5. Mediator

Actors:
1. components
2. client
3. mediator
Goal: add some new functionality by combining existing. 
   client communicate with mediator but not with components.  
   mediator - HUB of components communication.

Main class:

public class Mediator {
    
    public class Drawer {
        public String drawShape(String shape) {
            return "drawing:"+shape;
        }
    }
    
    public class Mover {
        public String moveShape(String shape) {
            return "moving:"+shape;
        }
    }
    
    public class ShapeMediator {
        Drawer drawer=new Drawer();
        Mover mover=new Mover();
        
        public String drawAndMove(String shape) {
            return drawer.drawShape(shape)+"."+mover.moveShape(shape);
        }
    }

}

Test class:

public class MediatorTest {

    @Test
    public void test() {
        Mediator mediator=new Mediator();
        Mediator.ShapeMediator shapeMediator=mediator. new ShapeMediator();
        String result=shapeMediator.drawAndMove("square");
        assertEquals("drawing:square.moving:square", result);
    }

}

6. Memento

Actors: 
 1. memento class
 2. client
 Goal: memento object saves it state on every change. 
   so, we can get it state, for every step we want.


Main class:


public class Memento {

    public class Shape {
        private int x;
        private int y;

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }

        public void moveTo(int x, int y) {
            this.x=x;
            this.y=y;
        }

    }

    public class ShapeMemento {
        private List<Shape> history=new ArrayList<Shape>();

        public void save(Shape shape) {
            Shape historyShape=new Shape();
            historyShape.moveTo(shape.getX(), shape.getY());
            history.add(historyShape);
        }

        public Shape getShapeForStep(int index) {
            Shape result=history.get(index);
            return result;
        }
    }

}


Test class:

public class MementoTest {

    @Test
    public void mementoTest(){
        Memento memento=new Memento();
        Memento.Shape shape=memento. new Shape();
        Memento.ShapeMemento shapeMemento=memento. new ShapeMemento();
        shape.moveTo(0,0);
        shapeMemento.save(shape);
        shape.moveTo(1,1);
        shapeMemento.save(shape);

        shape=shapeMemento.getShapeForStep(0);
        Assert.assertEquals(0, shape.getX());
        Assert.assertEquals(0, shape.getY());

        shape=shapeMemento.getShapeForStep(1);
        Assert.assertEquals(1, shape.getX());
        Assert.assertEquals(1, shape.getY());

    }
}

No comments:

Post a Comment