From Wikipedia, the free encyclopedia
In software engineering, behavioral 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.
- Observer pattern: aka Publish/Subscribe or Event Listener. Objects register to observe an event that may be raised by another object
- State pattern: A clean way for an object to partially change its type at runtime
- Strategy pattern: Algorithms can be selected on the fly
- Template method pattern: Describes the program skeleton of a program
- Visitor pattern: A way to separate an algorithm from an object
1. Observer
Actors:
1. event source(observable) - class which has method for registering (adding) observers
2. event handler(observer) - class which has method for reacting on event
Goal: event source is notifying observers objects
Main class:
public class Observer { StringBuilder log=new StringBuilder(); public String getLog() { return log.toString(); } public interface EventHandler { void onEvent(String event); } public class FirstHandler implements EventHandler { @Override public void onEvent(String event) { log.append("first:"+event+";"); } } public class SecondHandler implements EventHandler { @Override public void onEvent(String event) { log.append("second:"+event+";"); } } public class EventSource { List<EventHandler> eventHandlers=new ArrayList<EventHandler>(); public void addEventHandler(EventHandler handler) { eventHandlers.add(handler); } public void createEvent(String event) { for (EventHandler eventHandler: eventHandlers) { eventHandler.onEvent(event); } } } }
Test class:
public class ObserverTest { @Test public void test() { Observer observer=new Observer(); Observer.FirstHandler firstHandler=observer. new FirstHandler(); Observer.SecondHandler secondHandler=observer. new SecondHandler(); Observer.EventSource eventSource=observer. new EventSource(); eventSource.addEventHandler(firstHandler); eventSource.addEventHandler(secondHandler); eventSource.createEvent("test"); assertEquals("first:test;second:test;", observer.getLog()); } }
2. State
Actors:
1. set of state objects
2. object which can be in different states(with different assignments of state object)
Goal: object behavior depends on it state (state object)
Main class:
public class State { public interface ShapeState { String executeAction(); } public class CreateShapeState implements ShapeState { @Override public String executeAction() { return "create"; } } public class DrawShapeState implements ShapeState { @Override public String executeAction() { return "draw"; } } public class Shape { private ShapeState state; public ShapeState getState() { return state; } public void setState(ShapeState state) { this.state = state; } public String executeAction() { return state.executeAction(); } } }
Test class:
public class StateTest { @Test public void test() { State state=new State(); State.Shape shape=state. new Shape(); shape.setState(state. new CreateShapeState() ); assertEquals("create", shape.executeAction()); shape.setState(state. new DrawShapeState() ); assertEquals("draw", shape.executeAction()); } }
3. Strategy
Actors: 1. Strategy object 2. Context object which have Strategy object Goal: context execute action using strategy object so execution is based on strategy
Main class:
public class Strategy { interface DrawStrategy { String draw(); } public class FastDrawStrategy implements DrawStrategy { @Override public String draw() { return "fast draw"; } } public class SlowDrawStrategy implements DrawStrategy { @Override public String draw() { return "slow draw"; } } public class Context { DrawStrategy strategy; public void setStrategy(DrawStrategy strategy) { this.strategy=strategy; } public String executeStrategy() { return strategy.draw(); } } }
Test class:
public class StrategyTest { @Test public void test() { Strategy strategy=new Strategy(); Strategy.FastDrawStrategy fastDrawStrategy=strategy. new FastDrawStrategy(); Strategy.SlowDrawStrategy slowDrawStrategy=strategy. new SlowDrawStrategy(); Strategy.Context context=strategy. new Context(); context.setStrategy(fastDrawStrategy); assertEquals("fast draw", context.executeStrategy()); context.setStrategy(slowDrawStrategy); assertEquals("slow draw", context.executeStrategy()); } }
4. Template
Actors: 1. template class: one method of it can not be overriden - it is a TEMPLATE method 2. subclasses of template class Goal: strictly defined template of logic execution. detail of execution can be different for subclasses, by overriding non template methods
Main class:
public class Template { public abstract class ShapeTemplate { public abstract String create(); public abstract String draw(); public String createAndDraw() { return create() + "." + draw(); } } public class FastShape extends ShapeTemplate { @Override public String create() { return "fast create"; } @Override public String draw() { return "fast draw"; } } public class SlowShape extends ShapeTemplate { @Override public String create() { return "slow create"; } @Override public String draw() { return "slow draw"; } } }
Test class:
public class TemplateTest { @Test public void test() { Template template=new Template(); Template.FastShape fastShape=template. new FastShape(); Template.SlowShape slowShape=template. new SlowShape(); // String result=""; result=fastShape.createAndDraw(); assertEquals("fast create.fast draw", result); result=slowShape.createAndDraw(); assertEquals("slow create.slow draw", result); } }
5. Visitor
Actors:
1. Visitor. several visit(Element) - for every subclass of Element.
2.Element. Element has accept(Visitor) method.
Goal: logic separation: element calls visitor's method, which calls element's method
Main class:
public class Visitor { public interface ShapeVisitor { public String visit(Circle element); public String visit(Square element); } public abstract class Shape { public abstract void accept(ShapeVisitor visitor); public String draw() { return "drawing"; }; } public class Circle extends Shape { @Override public void accept(ShapeVisitor visitor) { visitor.visit(this); } } public class Square extends Shape { @Override public void accept(ShapeVisitor visitor) { visitor.visit(this); } } public class FastShapeVisitor implements ShapeVisitor { @Override public String visit(Circle element) { return "fast circle "+element.draw(); } @Override public String visit(Square element) { return "fast square "+element.draw(); } } }
Test class:
public class VisitorTest { @Test public void visitorTest() { Visitor visitor=new Visitor(); Visitor.FastShapeVisitor fastShapeVisitor=visitor. new FastShapeVisitor(); Visitor.Circle circle=visitor.new Circle(); Visitor.Square square=visitor. new Square(); String result=""; result=fastShapeVisitor.visit(circle); Assert.assertEquals("fast circle drawing", result); result=fastShapeVisitor.visit(square); Assert.assertEquals("fast square drawing", result); } }