Behavioral
1. Chain of Responsibility - delegates commands to a chain of processing
objects.
interface Chain {
public abstract void setNext(Chain nextInChain);
public abstract void process(Number request);
}
class Number {
private int number;
public Number(int number) {
this.number = number;
}
public int getNumber() {
return number;
}
}
class NegativeProcessor implements Chain {
private Chain nextInChain;
public void setNext(Chain c) {
nextInChain = c;
}
public void process(Number request) {
if (request.getNumber() < 0) {
System.out.println("NegativeProcessor : " +
request.getNumber());
} else {
nextInChain.process(request);
}
}
}
class ZeroProcessor implements Chain {
private Chain nextInChain;
public void setNext(Chain c) {
nextInChain = c;
}
public void process(Number request) {
if (request.getNumber() == 0) {
System.out.println("ZeroProcessor : " +
request.getNumber());
} else {
nextInChain.process(request);
}
}
}
class PositiveProcessor implements Chain {
private Chain nextInChain;
public void setNext(Chain c) {
nextInChain = c;
}
public void process(Number request) {
if (request.getNumber() > 0) {
System.out.println("PositiveProcessor : " +
request.getNumber());
} else {
nextInChain.process(request);
}
}
}
public class ChainOfResponsibilityExample {
public static void main(String[] args) {
// configure Chain of Responsibility
Chain c1 = new NegativeProcessor();
Chain c2 = new ZeroProcessor();
Chain c3 = new PositiveProcessor();
c1.setNext(c2);
c2.setNext(c3);
// calling chain of responsibility
c1.process(new Number(99));
c1.process(new Number(-30));
c1.process(new Number(0));
c1.process(new Number(100));
}
}
|
Chain of responsibility (recognizeable by behavioral methods which (indirectly) invokes
the same method in another implementation
of same abstract/interface
type in a queue)
2. Command - creates
objects which encapsulate actions and parameters.
import java.util.ArrayList;
import java.util.List;
interface ConsumerElectronics {
public abstract void on();
public abstract void mute();
}
class Television implements ConsumerElectronics {
public void on() {
System.out.println("Television is on!");
}
@Override
public void mute() {
System.out.println("Television is muted!");
}
}
class SoundSystem implements ConsumerElectronics {
public void on() {
System.out.println("Sound system is on!");
}
@Override
public void mute() {
System.out.println("Sound system is muted!");
}
}
interface Command {
public abstract void execute();
}
class OnCommand implements Command {
private ConsumerElectronics ce;
public OnCommand(ConsumerElectronics
ce) {
this.ce = ce;
}
public void execute() {
ce.on();
}
}
class MuteAllCommand implements Command {
List
public
MuteAllCommand(List
this.ceList = ceList;
}
@Override
public void execute() {
for (ConsumerElectronics ce : ceList) {
ce.mute();
}
}
}
class Button {
Command c;
public Button(Command c) {
this.c = c;
}
public void click() {
c.execute();
}
}
class UniversalRemote {
public static ConsumerElectronics
getActiveDevice() {
// here we will have a complex electronic circuit :-)
// that will maintain current device
Television
tv = new Television();
return tv;
}
}
|
Command (recognizeable by behavioral
methods in an abstract/interface type which invokes a method in an
implementation of adifferent abstract/interface
type which has been encapsulated by
the command implementation during its creation)
3. Interpreter - implements a specialized language.
import java.util.Stack;
interface IExpression {
public int interpret();
}
/**
Terminal Expression */
class NumberExpression implements IExpression {
int number;
public NumberExpression(int i) {
number = i;
}
public NumberExpression(String s) {
number = Integer.parseInt(s);
}
@Override
public int interpret() {
return number;
}
}
/**
Non-terminal expression */
class MultiplyExpression implements IExpression {
IExpression leftExpression;
IExpression rightExpresion;
public MultiplyExpression(IExpression
leftExpression,
IExpression
rightExpresion) {
this.leftExpression = leftExpression;
this.rightExpresion = rightExpresion;
}
@Override
public int interpret() {
return leftExpression.interpret() * rightExpresion.interpret();
}
}
class PlusExpression implements IExpression {
IExpression leftExpression;
IExpression rightExpresion;
public PlusExpression(IExpression
leftExpression, IExpression rightExpresion) {
this.leftExpression = leftExpression;
this.rightExpresion = rightExpresion;
}
@Override
public int interpret() {
return leftExpression.interpret() + rightExpresion.interpret();
}
}
class MinusExpression implements IExpression {
IExpression leftExpression;
IExpression rightExpresion;
public MinusExpression(IExpression
leftExpression,
IExpression
rightExpresion) {
this.leftExpression = leftExpression;
this.rightExpresion = rightExpresion;
}
@Override
public int interpret() {
return leftExpression.interpret() - rightExpresion.interpret();
}
}
/*-
* Postfix calculator.
*
* Algorithm for postfix
expression parser implementation is simpler than for
* infix.
*
* Read token one by one
and loop till end of expression
* Is read element a
number
* 1. true then, push it
to a stack
* 2. false then,
* 1. pop two elements from stack
* 2. apply the operator
* 3. push the result to stack
*
*/
public class InterpreterExample {
public static void main(String args[]) {
String
tokenString = "4 3 2 - 1 + *";
Stack
String[]
tokenList = tokenString.split(" ");
for (String s : tokenList) {
if (isOperator(s)) {
IExpression
rightExpression = stack.pop();
IExpression
leftExpression = stack.pop();
IExpression
operator = getOperatorInstance(s, leftExpression,
rightExpression);
int result = operator.interpret();
stack.push(new NumberExpression(result));
}
else {
IExpression
i = new NumberExpression(s);
stack.push(i);
}
}
System.out.println("Result: " +
stack.pop().interpret());
}
public static boolean isOperator(String s) {
if (s.equals("+") || s.equals("-") || s.equals("*"))
return true;
else
return false;
}
public static IExpression
getOperatorInstance(String s, IExpression left,
IExpression
right) {
switch (s) {
case "+":
return new PlusExpression(left, right);
case "-":
return new MinusExpression(left, right);
case "*":
return new MultiplyExpression(left,
right);
}
return null;
}
}
|
Interpreter (recognizeable by behavioral
methods returning a structurally different
instance/type of the given instance/type; note that parsing/formatting is not
part of the pattern, determining the pattern and how to apply it is)
4. Iterator - accesses
the elements of an object sequentially without exposing its underlying
representation.
import java.util.ArrayList;
import java.util.List;
class Animal {
private String animalName;
private String animalType;
public Animal(String animalName,
String animalType) {
this.animalName = animalName;
this.animalType = animalType;
}
public String getAnimalName() {
return animalName;
}
public void setAnimalName(String
animalName) {
this.animalName = animalName;
}
public String getAnimalType() {
return animalType;
}
public void setAnimalType(String
animalType) {
this.animalType = animalType;
}
}
interface Iterator {
public Animal nextAnimal();
public boolean isLastAnimal();
public Animal currentAnimal();
}
class WildIterator implements Iterator {
public List
private int position;
public
WildIterator(List
this.animalList = animalList;
}
@Override
public Animal nextAnimal() {
Animal
animal = null;
for (; position < animalList.size(); position++) {
if ("Wild".equals((animalList.get(position)).getAnimalType())) {
animal
= animalList.get(position);
position++;
break;
}
}
return animal;
}
@Override
public boolean isLastAnimal() {
for (int i = position; i < animalList.size(); i++) {
if ("Wild".equals((animalList.get(i)).getAnimalType())) {
return false;
}
}
return true;
}
@Override
public Animal currentAnimal() {
if (position < animalList.size()) {
return animalList.get(position);
}
return null;
}
}
class DomesticIterator implements Iterator {
List
private int position;
public
DomesticIterator(List
this.animalList = animalList;
}
@Override
public Animal nextAnimal() {
Animal
animal = null;
for (; position < animalList.size(); position++) {
if ("Domestic".equals((animalList.get(position)).getAnimalType())) {
animal
= animalList.get(position);
position++;
break;
}
}
return animal;
}
@Override
public boolean isLastAnimal() {
for (int i = position; i < animalList.size(); i++) {
if ("Domestic".equals((animalList.get(i)).getAnimalType())) {
return false;
}
}
return true;
}
@Override
public Animal currentAnimal() {
if (position < animalList.size()) {
return animalList.get(position);
}
return null;
}
}
interface IZoo {
public List
public void addAnimal(Animal animal);
public void removeAnimal(Animal animal);
public Iterator createIterator(String
iteratorType);
}
class ZooImpl implements IZoo {
List
public ZooImpl() {
animalList = new ArrayList
}
@Override
public List
return animalList;
}
@Override
public void addAnimal(Animal animal) {
animalList.add(animal);
}
@Override
public void removeAnimal(Animal animal) {
animalList.remove(animal);
}
@Override
public Iterator createIterator(String
iteratorType) {
if ("Wild".equals(iteratorType))
{
return new WildIterator(animalList);
} else {
return new DomesticIterator(animalList);
}
}
}
public class IteratorExample {
public static void main(String args[]) {
ZooImpl
zoo = new ZooImpl();
zoo.addAnimal(new Animal("Tiger", "Wild"));
zoo.addAnimal(new Animal("Lion", "Wild"));
zoo.addAnimal(new Animal("Tom Cat", "Domestic"));
zoo.addAnimal(new Animal("Raging Bull", "Wild"));
zoo.addAnimal(new Animal("Scooby Doo", "Domestic"));
Iterator
wildIterator = zoo.createIterator("Wild");
while (!wildIterator.isLastAnimal())
{
System.out.println("Wild Animal: "
+
wildIterator.nextAnimal().getAnimalName());
}
Iterator
domesticIterator = zoo.createIterator("Domestic");
while
(!domesticIterator.isLastAnimal()) {
System.out.println("Domestic Animal: "
+
domesticIterator.nextAnimal().getAnimalName());
}
}
}
|
Iterator (recognizeable by behavioral
methods sequentially returning instances of a different type from a queue)
As of Java 5, objects
implementing the Iterable interface,
which returns an
Iterator
from its only method, can be traversed using theenhanced for
loop syntax.[2] The Collection interface
from the Java
collections framework extends Iterable
.
5. Mediator - allows loose coupling between classes by being the only class that has
detailed knowledge of their methods.
interface IATCMediator {
public void registerRunway(Runway runway);
public void registerFlight(Flight flight);
public boolean isLandingOk();
public void setLandingStatus(boolean status);
}
interface ICommand {
void land();
}
class Flight implements ICommand {
private IATCMediator atcMediator;
public Flight(IATCMediator
atcMediator) {
this.atcMediator = atcMediator;
}
public void land() {
if (atcMediator.isLandingOk()) {
System.out.println("Landing done....");
atcMediator.setLandingStatus(true);
} else
System.out.println("Will wait to land....");
}
public void getReady() {
System.out.println("Getting ready...");
}
}
class Runway implements ICommand {
private IATCMediator atcMediator;
public Runway(IATCMediator
atcMediator) {
this.atcMediator = atcMediator;
atcMediator.setLandingStatus(true);
}
@Override
public void land() {
System.out.println("Landing permission granted...");
atcMediator.setLandingStatus(true);
}
}
class ATCMediator implements IATCMediator {
private Flight flight;
private Runway runway;
public boolean land;
public void registerRunway(Runway runway) {
this.runway = runway;
}
public void registerFlight(Flight flight)
{
this.flight = flight;
}
public boolean isLandingOk() {
return land;
}
@Override
public void setLandingStatus(boolean status) {
land = status;
}
}
public class MediatorExample {
public static void main(String args[]) {
IATCMediator
atcMediator = new ATCMediator();
Flight
sparrow101 = new Flight(atcMediator);
Runway
mainRunway = new Runway(atcMediator);
atcMediator.registerFlight(sparrow101);
atcMediator.registerRunway(mainRunway);
sparrow101.getReady();
mainRunway.land();
sparrow101.land();
}
}
|
Mediator (recognizeable by behavioral
methods taking an instance of different abstract/interface type (usually using
the command pattern) which delegates/uses the given instance)
6. Memento - provides
the ability to restore an object to its previous state (undo).
import java.util.ArrayList;
import java.util.List;
class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
class Originator {
// this String is just for example
// in real world application this
// will be a java class - the object
// for which the state to be stored
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
public Memento createMemento() {
return new Memento(state);
}
public void setMemento(Memento memento) {
state = memento.getState();
}
}
class Caretaker {
private List
public void addMemento(Memento m) {
statesList.add(m);
}
public Memento getMemento(int index) {
return statesList.get(index);
}
}
public class MementoExample {
public static void main(String[] args) {
Originator
originator = new Originator();
originator.setState("Lion");
Memento
memento = originator.createMemento();
Caretaker
caretaker = new Caretaker();
caretaker.addMemento(memento);
originator.setState("Tiger");
originator.setState("Horse");
memento
= originator.createMemento();
caretaker.addMemento(memento);
originator.setState("Elephant");
System.out
.println("Originator Current State: " + originator.getState());
System.out.println("Originator restoring to previous state...");
memento
= caretaker.getMemento(1);
originator.setMemento(memento);
System.out
.println("Originator Current State: " + originator.getState());
System.out.println("Again restoring to previous state...");
memento
= caretaker.getMemento(0);
originator.setMemento(memento);
System.out
.println("Originator Current State: " + originator.getState());
}
}
|
7. Observer - is
a publish/subscribe pattern which allows a number of observer objects to see an
event.
import java.util.ArrayList;
import java.util.List;
/*
* Same as Observable.
*/
interface Subject {
public void registerObserver(Observer
observer);
public void notifyObserver();
public void unRegisterObserver(Observer
observer);
public Object getUpdate();
}
class Blog implements Subject {
List
private boolean stateChange;
public Blog() {
this.observersList = new ArrayList
stateChange = false;
}
public void registerObserver(Observer
observer) {
observersList.add(observer);
}
public void unRegisterObserver(Observer
observer) {
observersList.remove(observer);
}
public void notifyObserver() {
if (stateChange) {
for (Observer observer : observersList) {
observer.update();
}
}
}
public Object getUpdate() {
Object
changedState = null;
// should have logic to send the
// state change to querying observer
if (stateChange) {
changedState
= "Observer Design Pattern";
}
return changedState;
}
public void postNewArticle() {
stateChange = true;
notifyObserver();
}
}
interface Observer {
public void update();
public void setSubject(Subject subject);
}
class User implements Observer {
private String article;
private Subject blog;
public void setSubject(Subject blog) {
this.blog = blog;
article = "No New Article!";
}
@Override
public void update() {
System.out.println("State change reported by Subject.");
article = (String) blog.getUpdate();
}
public String getArticle() {
return article;
}
}
public class ObserverExample {
public static void main(String args[]) {
Blog
blog = new Blog();
User
user1 = new User();
User
user2 = new User();
blog.registerObserver(user1);
blog.registerObserver(user2);
user1.setSubject(blog);
user2.setSubject(blog);
System.out.println(user1.getArticle());
blog.postNewArticle();
System.out.println(user1.getArticle());
}
}
|
Observer
(or Publish/Subscribe) (recognizeable by behavioral methods which invokes a method on an
instance of anotherabstract/interface
type, depending on own state)
8. State - allows
an object to alter its behavior when it’s internal state changes.
/**
* State interface.
*/
interface MobileAlertState {
public void alert(AlertStateContext ctx);
}
class Vibration implements MobileAlertState {
@Override
public void alert(AlertStateContext ctx) {
System.out.println("vibration...");
}
}
class Silent implements MobileAlertState {
@Override
public void alert(AlertStateContext ctx) {
System.out.println("silent...");
}
}
/**
* This class maintains
the current state and is the core of the state design
* pattern. A client
should access / run the whole setup through this class.
*/
class AlertStateContext {
private MobileAlertState currentState;
public AlertStateContext() {
currentState = new Vibration();
}
public void setState(MobileAlertState
state) {
currentState = state;
}
public void alert() {
currentState.alert(this);
}
}
public class StateExample {
public static void main(String[] args) {
AlertStateContext
stateContext = new AlertStateContext();
stateContext.alert();
stateContext.alert();
stateContext.setState(new Silent());
stateContext.alert();
stateContext.alert();
stateContext.alert();
}
}
|
State (recognizeable by behavioral
methods which changes its behaviour depending on the instance's state which can
be controlled externally)
·
javax.faces.lifecycle.LifeCycle#execute()
(controlled
by FacesServlet
, the behaviour is
dependent on current phase (state) of JSF lifecycle)
9. Strategy - allows
one of a family of algorithms to be selected on-the-fly at runtime.
/**
* The classes that
implement a concrete strategy should implement this. The
* Context class uses
this to call the concrete strategy.
*/
interface Strategy {
int execute(int a, int b);
};
/** Implements the algorithm using the strategy interface */
class Add implements Strategy {
public int execute(int a, int b) {
System.out.println("Called Add's execute()");
return a + b; // Do an addition with a and b
}
};
class Subtract implements Strategy {
public int execute(int a, int b) {
System.out.println("Called Subtract's execute()");
return a - b; // Do a subtraction with a and b
}
};
class Multiply implements Strategy {
public int execute(int a, int b) {
System.out.println("Called Multiply's execute()");
return a * b; // Do a multiplication with a and b
}
};
// Configured with a ConcreteStrategy object and maintains
// a reference to a Strategy object
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int a, int b) {
return this.strategy.execute(a, b);
}
};
/** Tests the pattern */
class StrategyExample {
public static void main(String[] args) {
Context
context;
// Three contexts following different strategies
context
= new Context(new Add());
int resultA =
context.executeStrategy(3, 4);
context
= new Context(new Subtract());
int resultB =
context.executeStrategy(3, 4);
context
= new Context(new Multiply());
int resultC =
context.executeStrategy(3, 4);
System.out.println("Result A : " + resultA);
System.out.println("Result B : " + resultB);
System.out.println("Result C : " + resultC);
}
}
|
Strategy and open/closed principle[edit]
According to the strategy
pattern, the behaviors of a class should not be inherited. Instead they should
be encapsulated using interfaces. As an example, consider a car class. Two
possible functionalities for car are brake and accelerate.
Since accelerate and brake
behaviors change frequently between models, a common approach is to implement
these behaviors in subclasses. This approach has significant drawbacks:
accelerate and brake behaviors must be declared in each new Car model. The work
of managing these behaviors increases greatly as the number of models
increases, and requires code to be duplicated across models. Additionally, it
is not easy to determine the exact nature of the behavior for each model
without investigating the code in each.
The strategy pattern uses
aggregation instead of inheritance. In the strategy pattern, behaviors are
defined as separate interfaces and specific classes that implement these
interfaces. Specific classes encapsulate these interfaces. This allows better
decoupling between the behavior and the class that uses the behavior. The
behavior can be changed without breaking the classes that use it, and the
classes can switch between behaviors by changing the specific implementation
used without requiring any significant code changes. Behaviors can also be
changed at run-time as well as at design-time. For instance, a car object’s
brake behavior can be changed from
BrakeWithABS()
to Brake()
by changing the brakeBehavior
member to:brakeBehavior = new Brake();
This gives greater flexibility in
design and is in harmony with the Open/closed principle (OCP) that states that classes should be open for extension but
closed for modification.
Strategy (recognizeable by behavioral
methods in an abstract/interface type which invokes a method in an
implementation of adifferent abstract/interface
type which has been passed-in as
method argument into the strategy implementation)
·
javax.servlet.http.HttpServlet
,
the service()
and all doXXX()
methods
takeHttpServletRequest
and HttpServletResponse
and
the implementor has to process them (and not to get hold of them as instance
variables!).
10. Template Method - defines the skeleton of an algorithm as an
abstract class, allowing its subclasses to provide concrete behavior.
The template method is used in
frameworks, where each implements the invariant parts of a domain's
architecture, leaving "placeholders" for customisation options. This
is an example for inversion of control, also called the Hollywood principle. Reasons to use the template
method are to:[4]
·
Avoid duplication in the code: the general workflow structure is
implemented once in the abstract class's algorithm, and
necessary variations are implemented in each of the subclasses.
·
Control at what point(s) subclassing is allowed. As opposed to a simple
polymorphic override, where the base method would be entirely rewritten
allowing radical change to the workflow, only the specific details of the
workflow are allowed to change.
The control structure (inversion of control) that is the result of the
application of a template pattern is often referred to as the Hollywood
Principle: "Don't call us, we'll call you." Using this principle, the
template method in a parent class controls the overall process by calling
subclass methods as required.
import java.util.Random;
/**
* An abstract class
that is common to several games in which players play
* against the others,
but only one is playing at a given time.
*/
abstract class Game {
protected int playersCount;
abstract void initializeGame();
abstract void makePlay(int player);
abstract boolean endOfGame();
abstract void printWinner();
/* A template method : */
public final void playOneGame(int playersCount) {
this.playersCount = playersCount;
initializeGame();
int j = 0;
while (!endOfGame()) {
makePlay(j);
j
= (j + 1) % playersCount;
}
printWinner();
}
}
// Now we can extend this class in order
// to implement actual games:
class Monopoly extends Game {
private int currentPlayer;
/* Implementation of necessary concrete methods */
void initializeGame() {
// Initialize players
// Initialize money
}
void makePlay(int player) {
// Process one turn of player
System.out.println("Playing player: " +
player);
this.currentPlayer = player;
}
boolean endOfGame() {
// Return true if game is over
// according to Monopoly rules
Random
rand = new Random();
return rand.nextInt(100) < 5 ? true : false;
}
void printWinner() {
// Display who won
System.out.println("Winner of Monopoly game is player: "
+
currentPlayer);
}
/* Specific declarations for the Monopoly game. */
// ...
}
class Chess extends Game {
private int currentPlayer;
/* Implementation of necessary concrete methods */
void initializeGame() {
// Initialize players
// Put the pieces on the board
}
void makePlay(int player) {
// Process a turn for the player
System.out.println("Playing player: " +
player);
this.currentPlayer = player;
}
boolean endOfGame() {
// Return true if in Checkmate or
// Stalemate has been reached
Random
rand = new Random();
return rand.nextInt(100) < 10 ? true : false;
}
void printWinner() {
System.out.println("Winner of Chess game is player: " + currentPlayer);
}
/* Specific declarations for the chess game. */
// ...
}
public class TemplateMethodExample {
public static void main(String[] args) {
Game g1 = new Chess();
g1.playOneGame(2);
Monopoly
m1 = new Monopoly();
m1.playOneGame(4);
}
}
|
Template method (recognizeable by behavioral methods which already have a
"default" behaviour definied by an abstract type)
·
All non-abstract methods of
java.io.InputStream
, java.io.OutputStream
, java.io.Reader
and java.io.Writer
.
·
All non-abstract methods of
java.util.AbstractList
, java.util.AbstractSet
andjava.util.AbstractMap
.
·
javax.servlet.http.HttpServlet
, all
the doXXX()
methods by default sends
a HTTP 405 "Method Not Allowed" error to the response. You're free to
implement none or any of them.
11. Visitor - separates
an algorithm from an object structure by moving the hierarchy of methods into
one object.
In the example below, every car element has
to do perform same algorithm (print and do, but in their own way) so we can
take out the algorithms into their own classes and invoke them when the
corresponding visit method is called. In future more algorithms may be added to
all car elements as a new class extending CarElementVisitor.
interface ICarElementVisitor {
void visit(Wheel wheel);
void visit(Engine engine);
void visit(Body body);
void visit(Car car);
}
interface ICarElement {
void accept(ICarElementVisitor
visitor); // CarElements have to provide
// accept().
}
class Wheel implements ICarElement {
private String name;
public Wheel(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void accept(ICarElementVisitor
visitor) {
/*
* accept(ICarElementVisitor) in Wheel implements
* accept(ICarElementVisitor) in ICarElement,
so the call to accept is
* bound at run time. This can be considered
the first dispatch.
* However, the decision to call visit(Wheel)
(as opposed to
* visit(Engine) etc.) can be made during compile
time since 'this' is
* known at compile time to be a Wheel.
Moreover, each implementation of
* ICarElementVisitor implements the
visit(Wheel), which is another
* decision that is made at run time. This
can be considered the second
* dispatch.
*/
visitor.visit(this);
}
}
class Engine implements ICarElement {
public void accept(ICarElementVisitor
visitor) {
visitor.visit(this);
}
}
class Body implements ICarElement {
public void accept(ICarElementVisitor
visitor) {
visitor.visit(this);
}
}
class Car implements ICarElement {
ICarElement[] elements;
public Car() {
// create new Array of elements
this.elements = new ICarElement[] { new Wheel("front left"),
new Wheel("front right"), new Wheel("back left"),
new Wheel("back right"), new Body(), new Engine() };
}
public void accept(ICarElementVisitor
visitor) {
for (ICarElement elem : elements) {
elem.accept(visitor);
}
visitor.visit(this);
}
}
class CarElementPrintVisitor implements ICarElementVisitor {
public void visit(Wheel wheel) {
System.out.println("Visiting " +
wheel.getName() + " wheel");
}
public void visit(Engine engine) {
System.out.println("Visiting engine");
}
public void visit(Body body) {
System.out.println("Visiting body");
}
public void visit(Car car) {
System.out.println("Visiting car");
}
}
class CarElementDoVisitor implements ICarElementVisitor {
public void visit(Wheel wheel) {
System.out.println("Kicking my " +
wheel.getName() + " wheel");
}
public void visit(Engine engine) {
System.out.println("Starting my engine");
}
public void visit(Body body) {
System.out.println("Moving my body");
}
public void visit(Car car) {
System.out.println("Starting my car");
}
}
public class VisitorExample {
public static void main(String[] args) {
ICarElement
car = new Car();
car.accept(new CarElementPrintVisitor());
car.accept(new CarElementDoVisitor());
}
}
|
No comments:
Post a Comment