You are on page 1of 15

Tutorial 6

Behavioural design patterns

Section 0:
1. Describe Behavioural Design Patterns according to Gamma et al.?

Answer Guide:

Behavioral patterns are concerned with algorithms and the assignment of


responsibilities between objects.
Behavioral patterns describe not just patterns of objects or classes but also the patterns
of communication between them.
These patterns characterize complex control flow that's difficult to follow at run-time.
They shift your focus away from flow of control to let you concentrate just on the way
objects are interconnected.

2. How do Behavioural Object Patterns work?

Answer Guide:

Behavioral object patterns use object composition rather than inheritance. Some
describe how a group of peer objects cooperate to perform a task that no single object
can carry out by itself.

3. Give examples of common Behavioural Design Patterns.

4. List out the top ten design patterns, in your opinion.


Answer Guide:
http://www.mail-archive.com/patterns-discussion@cs.uiuc.edu/msg00251.html
1. Observer (Behavioral)
2. Composite (Structural)
3. Singleton (Creational)
4. Abstract Factory (Creational)
5. Visitor(Behavioral)
6. Adapter (Structural)
7. Factory Method (Creational)
8. Template Method(Behavioral)
9. Command(Behavioral)
10. ?

Section A: Observer Design Pattern

1. What is the intention of the Observer Design Pattern?


Answer Guide
Define a one-to-many dependency between objects so that when one object changes
state, all its dependents are notified and updated automatically.
2. Draw the Observer Design Pattern Class Diagram.
Answer Guide:

Lab exercise:
Create the following classes
DvdReleaseByCategory
import java.util.ArrayList;
import java.util.ListIterator;

public class DvdReleaseByCategory {


String categoryName;
ArrayList subscriberList = new ArrayList();
ArrayList dvdReleaseList = new ArrayList();

public DvdReleaseByCategory(String categoryNameIn) {


categoryName = categoryNameIn;
}

public String getCategoryName() {


return this.categoryName;
}

public boolean addSubscriber(DvdSubscriber dvdSubscriber) {


return subscriberList.add(dvdSubscriber);
}

public boolean removeSubscriber(DvdSubscriber dvdSubscriber) {


ListIterator listIterator = subscriberList.listIterator();
while (listIterator.hasNext()) {
if (dvdSubscriber == (DvdSubscriber)(listIterator.next())) {
listIterator.remove();
return true;
}
}
return false;
}

public void newDvdRelease(DvdRelease dvdRelease) {


dvdReleaseList.add(dvdRelease);
notifySubscribersOfNewDvd(dvdRelease);
}

public void updateDvd(DvdRelease dvdRelease) {


boolean dvdUpdated = false;
DvdRelease tempDvdRelease;
ListIterator listIterator = dvdReleaseList.listIterator();
while (listIterator.hasNext()) {
tempDvdRelease = (DvdRelease)listIterator.next();
if (dvdRelease.getSerialNumber().
equals(tempDvdRelease.getSerialNumber())) {
listIterator.remove();
listIterator.add(dvdRelease);
dvdUpdated = true;
break;
}
}
if (dvdUpdated == true) {
notifySubscribersOfUpdate(dvdRelease);
} else {
this.newDvdRelease(dvdRelease);
}
}

private void notifySubscribersOfNewDvd(DvdRelease dvdRelease) {


ListIterator listIterator = subscriberList.listIterator();
while (listIterator.hasNext()) {
((DvdSubscriber)(listIterator.next())).
newDvdRelease(dvdRelease, this.getCategoryName());
}
}

private void notifySubscribersOfUpdate(DvdRelease dvdRelease) {


ListIterator listIterator = subscriberList.listIterator();
while (listIterator.hasNext()) {
((DvdSubscriber)(listIterator.next())).
updateDvdRelease(dvdRelease, this.getCategoryName() );
}
}
}

DvdSubscriber

public class DvdSubscriber {


private String subscriberName;

public DvdSubscriber(String subscriberNameIn) {


this.subscriberName = subscriberNameIn;
}

public String getSubscriberName() {


return this.subscriberName;
}

public void newDvdRelease(DvdRelease newDvdRelease,


String subscriptionListName) {
System.out.println("");
System.out.println("Hello " + this.getSubscriberName() +
", subscriber to the " +
subscriptionListName +
" DVD release list.");
System.out.println("The new Dvd " +
newDvdRelease.getDvdName() +
" will be released on " +
newDvdRelease.getDvdReleaseMonth() + "/" +
newDvdRelease.getDvdReleaseDay() + "/" +
newDvdRelease.getDvdReleaseYear() + ".");
}

public void updateDvdRelease(DvdRelease newDvdRelease,


String subscriptionListName) {
System.out.println("");
System.out.println("Hello " + this.getSubscriberName() +
", subscriber to the " +
subscriptionListName +
" DVD release list.");
System.out.println(
"The following DVDs release has been revised: " +
newDvdRelease.getDvdName() + " will be released on " +
newDvdRelease.getDvdReleaseMonth() + "/" +
newDvdRelease.getDvdReleaseDay() + "/" +
newDvdRelease.getDvdReleaseYear() + ".");
}
}
DvdRelease

public class DvdRelease {


private String serialNumber;
private String dvdName;
private int dvdReleaseYear;
private int dvdReleaseMonth;
private int dvdReleaseDay;

public DvdRelease(String serialNumber,


String dvdName,
int dvdReleaseYear,
int dvdReleaseMonth,
int dvdReleaseDay) {
setSerialNumber(serialNumber);
setDvdName(dvdName);
setDvdReleaseYear(dvdReleaseYear);
setDvdReleaseMonth(dvdReleaseMonth);
setDvdReleaseDay(dvdReleaseDay);
}

public void updateDvdRelease(String serialNumber,


String dvdName,
int dvdReleaseYear,
int dvdReleaseMonth,
int dvdReleaseDay) {
setSerialNumber(serialNumber);
setDvdName(dvdName);
setDvdReleaseYear(dvdReleaseYear);
setDvdReleaseMonth(dvdReleaseMonth);
setDvdReleaseDay(dvdReleaseDay);
}

public void updateDvdReleaseDate(int dvdReleaseYear,


int dvdReleaseMonth,
int dvdReleaseDay) {
setDvdReleaseYear(dvdReleaseYear);
setDvdReleaseMonth(dvdReleaseMonth);
setDvdReleaseDay(dvdReleaseDay);
}

public void setSerialNumber(String serialNumberIn) {


this.serialNumber = serialNumberIn;
}
public String getSerialNumber() {
return this.serialNumber;
}

public void setDvdName(String dvdNameIn) {


this.dvdName = dvdNameIn;
}
public String getDvdName() {
return this.dvdName;
}

public void setDvdReleaseYear(int dvdReleaseYearIn) {


this.dvdReleaseYear = dvdReleaseYearIn;
}
public int getDvdReleaseYear() {
return this.dvdReleaseYear;
}

public void setDvdReleaseMonth(int dvdReleaseMonthIn) {


this.dvdReleaseMonth = dvdReleaseMonthIn;
}
public int getDvdReleaseMonth() {
return this.dvdReleaseMonth;
}

public void setDvdReleaseDay(int dvdReleaseDayIn) {


this.dvdReleaseDay = dvdReleaseDayIn;
}
public int getDvdReleaseDay() {
return this.dvdReleaseDay;
}
}
TestDvdObserver

class TestDvdObserver {
public static void main(String[] args) {
DvdReleaseByCategory btvs =
new DvdReleaseByCategory("Buffy the Vampire Slayer");
DvdReleaseByCategory simpsons =
new DvdReleaseByCategory("The Simpsons");
DvdReleaseByCategory sopranos =
new DvdReleaseByCategory("The Sopranos");
DvdReleaseByCategory xfiles =
new DvdReleaseByCategory("The X-Files");

DvdSubscriber jsopra = new DvdSubscriber("Junior Soprano");


DvdSubscriber msimps = new DvdSubscriber("Maggie Simpson");
DvdSubscriber rgiles = new DvdSubscriber("Rupert Giles");
DvdSubscriber smulde = new DvdSubscriber("Samantha Mulder");
DvdSubscriber wrosen = new DvdSubscriber("Willow Rosenberg");

btvs.addSubscriber(rgiles);
btvs.addSubscriber(wrosen);
simpsons.addSubscriber(msimps);
sopranos.addSubscriber(jsopra);
xfiles.addSubscriber(smulde);
xfiles.addSubscriber(wrosen);

DvdRelease btvsS2 =
new DvdRelease("DVDFOXBTVSS20",
"Buffy The Vampire Slayer Season 2",
2002, 06, 11);
DvdRelease simpS2 =
new DvdRelease("DVDFOXSIMPSO2",
"The Simpsons Season 2",
2002, 07, 9);
DvdRelease soprS2 =
new DvdRelease("DVDHBOSOPRAS2",
"The Sopranos Season 2",
2001, 11, 6);
DvdRelease xfilS5 =
new DvdRelease("DVDFOXXFILES5",
"The X-Files Season 5",
2002, 04, 1);

btvs.newDvdRelease(btvsS2);
simpsons.newDvdRelease(simpS2);
sopranos.newDvdRelease(soprS2);
xfiles.newDvdRelease(xfilS5);

xfiles.removeSubscriber(wrosen);

xfilS5.updateDvdReleaseDate(2002, 5, 14);
xfiles.updateDvd(xfilS5);
}
}
Tut6-A3. Show how the names in the Observer DP map to DvdRelease program.
3. Which class is the observer, and which class is being observed?
Answer guide:
DvdReleaseByCategory – the class which is observed
DvdSubscriber – the observer
4. Draw the UML class diagrams for all the classes created.

Section B: Visitor Design Pattern

1. Draw a UML class diagram that represents the Visitor design pattern

Answer Guide:

- -- -- -- -- -- -> a. (parameter) dependency

| <- - -- -- -- -- -- - |
| |
| |
| |
| |
| |
| b. (local variable type) dependency |
| |
|- - - -- -- -- -- -- -- -- -- --> - -- -- -- -- -- -- -- -- -- -- |

2. When can the Visitor Design Pattern be used?

Answer Guide:

Use the Visitor pattern when


l an object structure contains many classes of objects with differing interfaces, and you want to

perform operations on these objects that depend on their concrete classes.


l

many distinct and unrelated operations need to be performed on objects in an object structure, and you
want to avoid "polluting" their classes with these operations. Visitor lets you keep related operations
together by defining them in one class. When the object structure is shared by many applications, use
Visitor to put operations in just those applications that need them.
l

the classes defining the object structure rarely change, but you often want to define new operations
over the structure. Changing the object structure classes requires redefining the interface to all
visitors, which is potentially costly. If the object structure classes change often, then it's probably
better to define the operations in those classes.
Lab Exercise

Create the following classes

Title Blurb Visitor

public abstract class TitleBlurbVisitor {


String titleBlurb;
public void setTitleBlurb(String blurbIn) {
this.titleBlurb = blurbIn;
}
public String getTitleBlurb() {
return this.titleBlurb;
}

public abstract void visit(BookInfo bookInfo);


public abstract void visit(DvdInfo dvdInfo);
public abstract void visit(GameInfo gameInfo);
}

Title Long Blurb Visitor

public class TitleLongBlurbVisitor extends TitleBlurbVisitor {


public void visit(BookInfo bookInfo) {
this.setTitleBlurb("LB-Book: " +
bookInfo.getTitleName() +
", Author: " +
bookInfo.getAuthor());
}

public void visit(DvdInfo dvdInfo) {


this.setTitleBlurb("LB-DVD: " +
dvdInfo.getTitleName() +
", starring " +
dvdInfo.getStar() +
", encoding region: " +
dvdInfo.getEncodingRegion());
}

public void visit(GameInfo gameInfo) {


this.setTitleBlurb("LB-Game: " +
gameInfo.getTitleName());
}
}

Title Short Blurb Visitor

public class TitleShortBlurbVisitor extends TitleBlurbVisitor {


public void visit(BookInfo bookInfo) {
this.setTitleBlurb("SB-Book: " + bookInfo.getTitleName());
}

public void visit(DvdInfo dvdInfo) {


this.setTitleBlurb("SB-DVD: " + dvdInfo.getTitleName());
}

public void visit(GameInfo gameInfo) {


this.setTitleBlurb("SB-Game: " + gameInfo.getTitleName());
}
}

Abstract Title Info

public abstract class AbstractTitleInfo {


private String titleName;
public final void setTitleName(String titleNameIn) {
this.titleName = titleNameIn;
}
public final String getTitleName() {
return this.titleName;
}

public abstract void accept(TitleBlurbVisitor titleBlurbVisitor);


}

Book Info

public class BookInfo extends AbstractTitleInfo {


private String author;

public BookInfo(String titleName, String author) {


this.setTitleName(titleName);
this.setAuthor(author);
}

public void setAuthor(String authorIn) {


this.author = authorIn;
}
public String getAuthor() {
return this.author;
}

public void accept(TitleBlurbVisitor titleBlurbVisitor) {


titleBlurbVisitor.visit(this);
}
}

DVD Info

public class DvdInfo extends AbstractTitleInfo {


private String star;
private char encodingRegion;

public DvdInfo(String titleName,


String star,
char encodingRegion) {
this.setTitleName(titleName);
this.setStar(star);
this.setEncodingRegion(encodingRegion);
}

public void setStar(String starIn) {


this.star = starIn;
}
public String getStar() {
return this.star;
}
public void setEncodingRegion(char encodingRegionIn) {
this.encodingRegion = encodingRegionIn;
}
public char getEncodingRegion() {
return this.encodingRegion;
}

public void accept(TitleBlurbVisitor titleBlurbVisitor) {


titleBlurbVisitor.visit(this);
}
}

Game Info

public class GameInfo extends AbstractTitleInfo {


public GameInfo(String titleName) {
this.setTitleName(titleName);
}

public void accept(TitleBlurbVisitor titleBlurbVisitor) {


titleBlurbVisitor.visit(this);
}
}

Test Title Visitor

class TestTitleVisitor {
public static void main(String[] args) {
AbstractTitleInfo bladeRunner =
new DvdInfo("Blade Runner", "Harrison Ford", '1');
AbstractTitleInfo electricSheep =
new BookInfo("Do Androids Dream of Electric Sheep?",
"Phillip K. Dick");
AbstractTitleInfo sheepRaider =
new GameInfo("Sheep Raider");

TitleBlurbVisitor titleLongBlurbVisitor =
new TitleLongBlurbVisitor();

System.out.println("Long Blurbs:");
bladeRunner.accept(titleLongBlurbVisitor);
System.out.println("Testing bladeRunner " +
titleLongBlurbVisitor.getTitleBlurb());
electricSheep.accept(titleLongBlurbVisitor);
System.out.println("Testing electricSheep " +
titleLongBlurbVisitor.getTitleBlurb());
sheepRaider.accept(titleLongBlurbVisitor);
System.out.println("Testing sheepRaider " +
titleLongBlurbVisitor.getTitleBlurb());

TitleBlurbVisitor titleShortBlurbVisitor =
new TitleShortBlurbVisitor();
System.out.println("Short Blurbs:");
bladeRunner.accept(titleShortBlurbVisitor);
System.out.println("Testing bladeRunner " +
titleShortBlurbVisitor.getTitleBlurb());
electricSheep.accept(titleShortBlurbVisitor);
System.out.println("Testing electricSheep " +
titleShortBlurbVisitor.getTitleBlurb());
sheepRaider.accept(titleShortBlurbVisitor);
System.out.println("Testing sheepRaider " +
titleShortBlurbVisitor.getTitleBlurb());
}
}

Tut6-B1. Show how the names in the Visitor DP map to the Blurb & TitleInfo program. [1m]

1. Name the classes that plays the following roles:


I. Abstract Visitor
II. Concrete Visitor
III. Abstract Visitee
IV. Concrete Visitee

Answer Guide:

I. Abstract Visitor - TitleBlurbVisitor.java


II. Concrete Visitor - TitleLongBlurbVisitor.java or TitleShortBlurbVisitor.java
III. Abstract Visitee - AbstractTitleInfo.java
IV. Concrete Visitee – BookInfo, DVD Info , GameInfo

Tut6-B2. In applying Visitor design pattern (DP), draw the Class Diagram for Tut6-Section B, which
consists of AbstractTitleInfo with its accept(TitleBlurbVisitor) method, BookInfo with
setAuthor(String), setISBN(String) methods; DVDInfo & GameInfo, TestTitleVisitor,
{TitleLongBlurbVisitor, and TitleShortBlurbVisitor} with their visit(BookInfo), visit(DvdInfo),
visit(GameInfo) methods. [1m]

2. Draw the relevant UML class diagrams


3. Books now require that their ISBN numbers be recorded. Adjust the code accordingly, to
demonstrate the Visitor design pattern.
Answer guide:
Adjust this part of the code:

public class BookInfo extends AbstractTitleInfo {


private String author;

public BookInfo(String titleName, String author, String ISBN) {


this.setTitleName(titleName);
this.setAuthor(author);
this.setISBN(ISBN);
}
And so on…
Point out that the Abstract Title Info should not be adjusted, as the visitor pattern is not
reflected if its done that way
Section C: Template Method Design Pattern

1. Describe situations in which Template Method is suitable to be used?


Answer guide

to implement the invariant parts of an algorithm once and leave it up to subclasses to


implement the behavior that can vary.

lwhen common behavior among subclasses should be factored and localized in a common
class to avoid code duplication. You first identify the differences in the existing code and
then separate the differences into new operations. Finally, you replace the differing code with
a template method that calls one of these new operations.

lto control subclasses extensions. You can define a template method that calls "hook"
operations (see Consequences) at specific points, thereby permitting extensions only at those
points.
2. What is the structure of Template Method?
Answer Guide

Section D: Command Design Pattern

1. What is the structure of the Command Design Pattern?

2. How can Command be used?


Answer guide
parameterize objects by an action to perform, as MenuItem objects did above. You can express
such parameterization in a procedural language with a callback function, that is, a function that's
registeredsomewhere to be called at a later point. Commands are an object-oriented replacement
for callbacks.

lspecify, queue, and execute requests at different times. A Command object can have a lifetime
independent of the original request. If the receiver of a request can be represented in an address
space independent way, then you can transfer a command object for the request to a different
process and fulfill the request there.

lsupport undo. The Command's Execute operation can store state for reversing its effects in the
command itself. The Command interface must have an added Unexecute operation that reverses
the effects of a previous call to Execute. Executed commands are stored in a history list.
Unlimited-level undo and redo is achieved by traversing this list backwards and forwards calling
Unexecute and Execute, respectively.

lsupport logging changes so that they can be reapplied in case of a system crash. By augmenting
the Command interface with load and store operations, you can keep a persistent log of changes.
Recovering from a crash involves reloading logged commands from disk and reexecuting them
with the Execute operation.

lstructure a system around high-level operations built on primitives operations. Such a structure is
common in information systems that support transactions. A transaction encapsulates a set of
changes to data. The Command pattern offers a way to model transactions. Commands have a
common interface, letting you invoke all transactions the same way. The pattern also makes it
easy to extend the system with new transactions.

Lab exercise

Create the following

DvDName

public class DvdName {


private String titleName;

public DvdName(String titleName) {


this.setTitleName(titleName);
}

public final void setTitleName(String titleNameIn) {


this.titleName = titleNameIn;
}
public final String getTitleName() {
return this.titleName;
}

public void setNameStarsOn() {


this.setTitleName(this.getTitleName().replace(' ','*'));
}
public void setNameStarsOff() {
this.setTitleName(this.getTitleName().replace('*',' '));
}
public String toString() {
return ("DVD: " + this.getTitleName());
}
}

CommandAbstract

public abstract class CommandAbstract {


public abstract void execute();
}

DvdCommandNameStarsOn

public class DvdCommandNameStarsOn extends CommandAbstract {


private DvdName dvdName;

public DvdCommandNameStarsOn(DvdName dvdNameIn) {


this.dvdName = dvdNameIn;
}
public void execute() {
this.dvdName.setNameStarsOn();
}
}

DvdCommandNameStarsOff

public class DvdCommandNameStarsOff extends CommandAbstract {


private DvdName dvdName;

public DvdCommandNameStarsOff(DvdName dvdNameIn) {


this.dvdName = dvdNameIn;
}
public void execute() {
this.dvdName.setNameStarsOff();
}
}

1. Create the main file to test the classes, with the following results

as first instantiated
DVD: Jay and Silent Bob Strike Back
DVD: Sponge Bob Squarepants - Nautical Nonsense and Sponge Buddies

stars on
DVD: Jay*and*Silent*Bob*Strike*Back
DVD: Sponge*Bob*Squarepants*-*Nautical*Nonsense*and*Sponge*Buddies

sponge stars off


DVD: Jay*and*Silent*Bob*Strike*Back
DVD: Sponge Bob Squarepants - Nautical Nonsense and Sponge Buddies

Answer guide
class TestCommand {
public static void main(String[] args) {
DvdName jayAndBob =
new DvdName("Jay and Silent Bob Strike Back");
DvdName spongeBob =
new DvdName("Sponge Bob Squarepants - " +
"Nautical Nonsense and Sponge Buddies");
System.out.println("as first instantiated");
System.out.println(jayAndBob.toString());
System.out.println(spongeBob.toString());

CommandAbstract bobStarsOn =
new DvdCommandNameStarsOn(jayAndBob);
CommandAbstract bobStarsOff =
new DvdCommandNameStarsOff(jayAndBob);
CommandAbstract spongeStarsOn =
new DvdCommandNameStarsOn(spongeBob);
CommandAbstract spongeStarsOff =
new DvdCommandNameStarsOff(spongeBob);

bobStarsOn.execute();
spongeStarsOn.execute();
System.out.println(" ");
System.out.println("stars on");
System.out.println(jayAndBob.toString());
System.out.println(spongeBob.toString());

spongeStarsOff.execute();
System.out.println(" ");
System.out.println("sponge stars off");
System.out.println(jayAndBob.toString());
System.out.println(spongeBob.toString());
}
}

Tut6-D2. Show how the names in the Command DP map to DvdStarsOnOff program.

You might also like