0% found this document useful (0 votes)
3 views

Design Patterns and Frameworks_ 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM)

The document discusses design patterns and frameworks in software engineering, highlighting their importance in solving recurring problems in object-oriented programming. It categorizes 23 design patterns into creational, structural, and behavioral types, providing a common vocabulary for developers. The document also introduces specific patterns like Singleton and Factory, explaining their implementation and benefits in creating flexible and maintainable code.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

Design Patterns and Frameworks_ 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM)

The document discusses design patterns and frameworks in software engineering, highlighting their importance in solving recurring problems in object-oriented programming. It categorizes 23 design patterns into creational, structural, and behavioral types, providing a common vocabulary for developers. The document also introduces specific patterns like Singleton and Factory, explaining their implementation and benefits in creating flexible and maintainable code.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 35

Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

Design Patterns and Frameworks

4. Design Patterns and Frameworks


Software engineers with considerable experience in developing large applications have
found that typical problems often recur. For example, creating graphical views of data
which must update as the data changes. This experience has, in some cases, been
distilled into "patterns" of good design. Here, we take a look at some of the more
important patterns that have been created from experience in writing object-oriented
programming.

This unit explores a number of standard design patterns representing proven solutions to
recurring software engineering problems. The unit also considers frameworks that offer
an out-of-the-box implementation and dictate the architecture of an application.

The 23 prominent patterns representing reusable object-oriented design, can be


categorised into:

creational
concerned with object creation

structural
concerned with static composition of classes and objects into a program structure

behavioural
concerned with management of complex behaviour of objects and classes

Examples of some of these patterns and their typical use will be discussed in the
following sessions.

This unit contains several different design patterns. It is a good idea to


Tip focus on one session at a time, read about the patterns, try out the
example code, and think of some further examples of your own.
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 1 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

4.1. Design Patterns


Design patterns capture the lessons distilled from experience of expert software
developers, and present generalised solutions to recurring structural (as opposed to
algorithmic) problems and architectural challenges in object-oriented software design.
They provide a way of discussing the design of software at a higher/abstract level than
the raw code.

Each pattern aims to solve a problem within a given context and:

captures expertise of experienced designers;

supports reuse;

Design Patterns are descriptions of problems and the essence of their solutions, and
reflect accumulated wisdom and experience of software designers. Patterns capture
these proven solutions for reuse in software design. In effect, patterns facilitate
experience and design reuse as opposed to code reuse (though they often do this, too).

improves software stability, through use of proven approaches;

Patterns not only describe how software is structured, but also how classes and objects
interact, especially at run time. Taking these interactions and their consequences
explicitly into account leads to more flexible and reusable software.

provides a common vocabulary for developers talking about software.

As well as being tested solutions to common problems, patterns can be used as a shared
vocabulary for understanding and discussing object-oriented software design. This
enables communication among design and development teams in terms of the patterns to
use.

The art and science of design patterns was introduced to the world of software
engineering by the seminal book Design Patterns: Elements of Reusable Object-Oriented
Software by Gamma, Helm, Johnson, and Vlissides, commonly referred to as the "Gang
of Four" (GoF). The book introduced a catalogue of 23 patterns for use in object-oriented

https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 2 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

software projects.

Other, more recent catalogues extend this repertoire, and most importantly, extend
coverage to more specialized types of problems, e.g. problems involving concurrency or
patterns for multi-tier applications.

The Gang of Four define a Design Pattern as, "a solution to a problem in a context"; the
words in italics being the essence of a pattern. The other essential elements of a pattern
are its name and classification, its intent, and a statement of the consequences of
applying the pattern.

The GoF book structures 23 classic design patterns representing a set of qualities,
characteristics, and constraints, into three distinct categories based on their purpose:

Creational
These patterns control object creation, initialisation, and class selection. They include:

Singleton: ensures a single instance for a class.

Factory (Factory Method and Abstract Factory): lets a class defer its instantiation to
subclasses.

Other patterns in this category are Builder and Prototype. These are not covered in this
unit as they are less commonly applied in Java.

Structural
The patterns in this category organise relationships between classes and objects,
providing guidelines for combining and using related objects. They include:

Composite: allows objects to be composed into tree structures to represent part-


whole hierarchies.

Decorator: attach additional responsibilities to objects dynamically.

Other patterns in this category are Adapter, Bridge, Facade, Flyweight and Proxy.

Behavioural
These patterns control communication, messaging, and interaction between objects.
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 3 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

These patterns control communication, messaging, and interaction between objects.


They include:

Iterator: enables access to the elements of an aggregate object sequentially without


exposing its underlying representation.

Observer: helps in defining a one-to-many dependency between objects.

Template Method: lets subclasses redefine some steps of an algorithm without


changing the algorithm’s structure.

Strategy: enables defining a family of algorithms, encapsulating them and making


them interchangeable.

Other patterns in this category are Chain of Responsibility, Command, Interpreter,


Mediator, Memento, State and Visitor.

Patterns are often classified by a second criterion, their scope, based on their applicability
to classes and objects:

Class Patterns describe how relationships between classes and subclasses are
defined through inheritance. Relationships in class patterns are static and established
at compile time. The patterns in this category are Template Method and Factory
Method (others being, Adapter and Interpreter).

Object Patterns describe relationships between objects and are primarily defined by
composition. Relationships in object patterns are typically created at runtime and are
more dynamic and flexible. The patterns in this category are Singleton, Composite,
Decorator, Iterator, Observer and Strategy (others being, Facade, Proxy, Abstract
Factory, Visitor, etc).

Since designs must be eventually implemented in code, Design Patterns also provide
sample programming language (C++ or Java) code to illustrate the implementation.

This unit aims to familiarise you with some of these original GoF patterns and help you to
see how these patterns work and how architectural design choices are made on their
basis. The unit covers basic Java implementation of patterns. This is accompanied by
their visualisation using class diagrams depicting the behaviours and relationships among
classes.
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 4 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

classes.

You should aim to understand the intent of each pattern to appreciate when the pattern
may be applied and the results and trade-offs of applying it. Do bear in mind that patterns
are not concrete design descriptions, but a template for a design solution that can be
instantiated in different ways to suit the needs of specific applications. Sometimes the
patterns can be used directly, but sometimes they provide sources of inspiration.

4.2. Creational Patterns


Creational patterns deal with object creation, decoupling a client from the way objects are
created, composed, and represented. These patterns are used when a decision must be
made at the time a class is instantiated. The two recurring themes in these patterns are: i)
they hide how class instances are created and composed, and ii) they encapsulate
knowledge about the concrete classes the client uses.

Creational patterns provide an alternative for the standard object creation procedure in
Java using the new operator. The issue with concrete class instantiation (an
implementation as opposed to an interface) using new is that it often leads to coupling or
dependency problems, making the code inflexible. These patterns provide a way to
decouple a client from the objects it needs to instantiate. We will see an example of this
in the Factory pattern.

This session explores:

1. Singleton

2. Factory

4.2.1. Singleton Pattern


The Singleton pattern, for example, is used to encapsulate the creation of an object in
order to maintain control over it. This not only ensures that only one object is created, but
also allows "lazy instantiation"; that is, the instantiation of the object can be delayed until
it is actually needed. This is a better practice from the alternative, "eager initialisation",
from an object-oriented programming viewpoint.

The intent of the Singleton pattern as defined in Design Patterns is to, "ensure a class
has only one instance, and provides a [single,] global point of access to it".
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 5 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

has only one instance, and provides a [single,] global point of access to it".

The singleton pattern is based on a single class that holds a reference to the only
instance of itself while controlling its creation and its access via a single getter method.

This pattern is useful when only one object is needed to coordinate a set of actions.

This is a general class diagram for Singleton, showing a private static property of a
Singleton object as well as a public method (Instance()) that returns the property. This is
the core of what makes a Singleton. The other properties and methods represent
additional operations that may be allowed on the class. Clients access any instance of a
Singleton only through the Instance method.

Implementing the Singleton Pattern in code


We will illustrate the use of Singleton with a simple Logging framework; a framework
which is used to manage messages from within a running application, typically used for
debugging purposes. A real logger will output all messages to a file from where they can
be printed.

The Logger class:

public class SimpleLogger {


private int ERROR = 1; // levels for message types
private int WARNING = 2;
private int level; // the current level

// constructor, sets up level for logger


public SimpleLogger (int level) {
this.level = level;
}

// displays error message only if level is no less than ERROR


public void error (String msg) {
if (level >= ERROR) {
System.out.println ("Error: " + msg);
}
}
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 6 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

// displays warning message if level is WARNING (i.e., 2)


public void warning (String msg) {
if (level >= WARNING) {
System.out.println ("Warning: " + msg);
}
}
}

We can use the above logger class as follows:

SimpleLogger logger = new SimpleLogger (2); // display warning


// some code
logger.error ("some bug in your code!"); // this error is shown as its level is
less than WARNING

However, this can cause a problem when we wish to use the Logger class from multiple
other classes in our program. Although we can pass the Logger instance explicitly to
every class, we will end up with references to it in various parts of the program, impacting
code maintainability.

The solution is to utilise the Singleton pattern to provide access to a single global
instance from the SimpleLogger class itself. In Java, a Singleton class can be defined
using a static variable which is accessible globally, as follows:

public class SingletonLogger {


// ...
private static SingletonLogger uniqueInstance; // a static variable to hold one
instance of the class SingletonLogger

// other useful instance variables here

private SingletonLogger(){} // the constructor is declared private; only Single


tonLogger can instantiate this class

public static SingletonLogger getInstance () { // method to instantiate the clas


s and return an instance of it
if (uniqueInstance == null) { // if instance does not exist
uniqueInstance = new SingletonLogger (2); // create it - Notice that the le
vel is set here
}
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 7 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

}
return uniqueInstance; // return the single instance
}
// other public methods here. Singleton is a normal class; it may have other use
ful instance variables and methods
}

The Logger can be accessed from any part of the code using:

SingletonLogger.getInstance();

Notice the different aspects at play here. First of all, direct instantiation of objects (new
instances of this class) is prohibited by making the constructor private. Second, the single
instance is accessed calling the public static getInstance() method. Third, the singleton
class can now be constructed whenever needed, but will throw an error if you try to
construct it more than once.

4.2.2. Factory Pattern


This pattern is used to decide at run time which one of several compatible classes is to
be instantiated. This pattern is used throughout the Java API.

The Factory pattern, more specifically the Simple Factory pattern, provides a way to
decouple the clients from a concrete class through abstraction.

The class diagram above of this pattern shows the interface or abstract class that allows
instantiation of concrete classes by clients. This is explained further in the following:

Implementing the Factory Pattern in code


https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 8 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

Implementing the Factory Pattern in code


When you have a set of related concrete classes, often you’re forced to write code like
this:

Audiotype audio;

if ("MP3")) {
audio = new MP3Player();
} else if ("WAV")) {
audio = new WavPlayer ();
} else if ("AIFF")) {
audio = new AiffPlayer ();
}

Here we have several concrete audio classes, and the decision of the specific one to
instantiate is made at runtime depending on some conditions. Code that makes use of
several concrete classes is error-prone and difficult to maintain and update when it needs
to be changed to add new concrete classes.

This issue can be addressed by utilising the Factory pattern, which helps in defining an
abstract class or interface that handles the details of object creation (for all audio types)
through encapsulation. This assists in keeping the code flexible for modification, while
allowing creation of new instance(s) of a concrete class.

The following shows how the Factory pattern enables encapsulating the parts of code
that change when a new audio type is added from the rest of the application which
remains unchanged. The first step is to separate the object creation code into a new
class (PlayerFactory) that encapsulates object creation for all audios for its clients. Any
other object that needs a new audio to be created, has to come to this object.

public class PlayerFactory { // (1)


public Audiotype createAudio (String type) { // (2)
Audiotype audio; // creating an instance variable

if (type.equals("MP3")) { // code is parameterised by the type of audio


audio = new MP3Player(); // // (3)
} else if (type.equals("WAV")) {
audio = new WavPlayer ();
}
audio.play();

https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 9 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

return audio;
}
}

1. new class, the PlayerFactory, which has the task of creating audio types for its clients

2. First we define a createAudio() method in the factory (which all clients will use to
instantiate new objects) and pass the type of audio to it

3. Based on the type of audio, the correct concrete class is instantiated and assigned to
the audio instance variable. Notice that each audio here has to implement the
Audiotype interface.

Once we have created the interface or Factory (in the form of the createAudio method),
we can create a method (orderAudio) that becomes a client of the Factory and relies on it
for the creation of new audio objects.

public class AudioStore {

PlayerFactory factory; // (1)

public AudioStore(PlayerFactory factory) { // (2)


this.factory = factory;
}

public Audiotype orderAudio(String type) {

Audiotype audio;

audio = factory.createAudio(type); // (3)


audio.play(); // (4)
return audio;
}
// other methods
}

1. we now give AudioStore a reference to a PlayerFactory

2. AudioStore gets the factory passed to it in the constructor

3. the orderAudio() method uses the factory to create its audios by simply passing on
the type of the order. Notice that the new operator has been replaced with a create
method (createAudio()) on the factory object to prevent concrete instantiations

https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 10 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

4. this code does not change, but just operates on the type of audio

Now, the orderAudio method does not need to know about the various audio types (MP3,
WAV, etc). It can simply get an audio that implements the Audiotype interface, so that it
can call play() or any other relevant method. This prevents concrete instantiations from
the client code.

Notice that although we have seen only one here, the PlayerFactory class can have
many clients. By encapsulating the audio type creation in one class, we can ensure that
modification in code is made in only one place when the implementation changes: the
PlayerFactory is the only class responsible for returning the appropriate player class for
each type of audio file.

This design pattern is a good illustration of cohesion and reducing coupling. By


separating out the responsibility for the object construction into its own class, no other
class needs to be aware of the different file types or how to handle them. This design is
robust, as it is clear how to extend the code if a new audio type appears on the market.

The Simple Factory pattern has two variations: the Factory Method (a class creational
pattern) and the Abstract Factory (an object creational pattern). All Factory patterns
promote loose coupling by reducing dependencies of applications on concrete classes,
simplifying refactoring of code.

Factory Method
The intent of the Factory Method as defined in GoF Design Patterns is to "define an
interface for creating an object, but let subclasses decide which class to instantiate."

Where it deviates from the Simple Factory is that, instead of handling object creation in a
separate class (as is the case in Simple Factory), the Factory Method encapsulates it in a
subclass; decoupling the client code in the superclass from the object creation code in
the subclass.

4.3. Structural Patterns


Structural patterns provide a way of composing and organising classes and objects into
larger structures. These patterns are concerned with how classes inherit from each other
or how they are composed from other classes.
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 11 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

or how they are composed from other classes.

This session explores:

1. Composite

2. Decorator

The primary difference between these two patterns is that Composite composes multiple
components, while a Decorator decorates a single component.

4.3.1. Composite Pattern


The Composite pattern prescribes grouping or recursive composition of complex objects.
The intent of the Composite pattern as defined in Design Patterns is to, "compose objects
into tree structures to represent part-whole hierarchies." The Composite pattern provides
a structure to hold individual objects and compositions of objects and allows clients to
treat them uniformly.

The class hierarchies consist of primitive objects and composite objects. Primitive
objects, which might themselves be composed of objects (a composite), can be
composed into more complex objects, and so on recursively. Forcing relationships into a
part-whole hierarchy in this way minimises the types of objects that a system needs to
manage. Examples of the Composite class can be found in a graphical user interface, in
which a window can contain other widgets. For example, a window can contain a list box
which contains a button.

The Composite pattern makes it easy to model a "has a" relationship, which is particularly
helpful for modelling a tree structure in which every concept/element has its own class.

A typical example of a problem benefitting from the composite pattern is the


representation of a file system. In a file system, there are individual objects (files) and
composites of objects (folders). Folders can contain files and/or other folders, which
themselves contain files and/or folders. We can think of this representation as a tree, with
the parent folder at the top of the tree, and child folders representing further branch
points.

The solution is to use polymorphism to support tree traversal, without requiring any
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 12 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

pointers or explicit recursion.

In this tree structure, elements with a child/children are called nodes. An element without
a child is called a leaf. In the example of folders/files, the Leaf class would be a File, and
the Composite class the Folder.

Notice the different aspects at play here. First of all, the Client uses the Component
interface to access and manipulate the objects (Leaf and Composite) in the composition.
Second, the Component defines an interface for all objects in the composition; both the
composite and the leaf nodes. Third, the Component may implement a default behaviour
and operations for add() and remove(). Fourth, the Composite’s role is to define
behaviour of the components having children. The Composite also implements Leaf-
related operations.

Implementing the Composite Pattern in code

// an interface (abstract class) to support the Composite pattern


public interface Component {
void show ();
}

// the Leaf class


public class File implements Component {
private int size;
private String name;

public File (String name, int size) {


this.size = size;
this.name = name;
}

// the leaf object shows details of itself


public void show () {
System.out.println (name + ": " + size);
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 13 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

System.out.println (name + ": " + size);


}
}

// the Composite class


public class Folder implements Component {
private List<Component> contents;
private String name;

public Folder (String name) {


this.name = name;
contents = new ArrayList<Component> (); // Folder can have any number of child
ren
// of type Component. An internal Arra
yList
// is used to hold these.

public void add (Component c) {


contents.add (c);
}

// The composite object must show each of its contents in turn


public void show () {
System.out.println ("Folder: " + name);
for (Component c : contents) {
c.show ();
}
}
}

public class Demo {


public static void main (String[] args) {
File f1 = new File ("file1", 1000);
File f2 = new File ("file2", 1000);
File f3 = new File ("file3", 1000);
Folder d1 = new Folder ("folder1");
Folder d2 = new Folder ("folder2");
// place files/folders into a hierarchy
d1.add (d2)
d2.add (f1)
d1.add (f2)
d1.add (f3)
// use the Composite pattern to show the contents of the hierarchy
d1.show ();
// or an individual file
f1.show ();
}
}

https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 14 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

The above code illustrates use of the Composite design pattern. Notice how the show
method is implemented differently in the File (Leaf) class and in the Folder (Composite)
class. In the latter, the show method is called on each of the components of the folder.
The example main code demonstrates how easy it is to set up and show information
about individual files or nested hierarchies of folders.

This design pattern demonstrations good cohesion. Each class performs just one task.
The leaf class, File, is responsible for showing itself. The composite class, Folder, passes
off responsibility for showing its contents to those contents themselves. There is no place
in the code which explicitly works through the entire hierarchy - all is managed implicitly
using polymorphism and recursion. This design is robust, you can see there are no
limitations (beyond those of memory in the Java runtime), and clear. It is also easy to
extend without affecting any of the existing classes: think about adding a symbolic link,
which is a reference to another file - is it clear this would be simply another kind of leaf
object?

The only disadvantage to this pattern is a certain degree of opaqueness - is it clear that
the call to d1.show() is going to show the entire contents of the hierarchy? You do need to
understand the pattern in detail and the individual classes to appreciate exactly how
things are happening. Hence, if you are going to use this, or any other design pattern, in
your own code, it is important to document your intent and use clearly named methods.

We will meet further examples of the Composite class later in this module, most notably
when looking at the Swing API. In a graphical user interface, a window can contain other
widgets recursively, for example, a window can contain a list box which contains a button.
There, the Component class will represent the Leaf class, and the Container class the
Composite.

4.3.2. Decorator Pattern


The Decorator pattern prevents overuse of inheritance by decorating classes at runtime
through composition and delegation, ensuring flexible designs for extending functionality.
The intent of the Decorator pattern as defined in Design Patterns is to, "attach additional
responsibilities to an object dynamically." This enables giving objects new responsibilities
(by writing new code) without making any code changes in the underlying classes.

https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 15 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

This pattern is commonly used in GUI programming, so we will include an example from
this context. Sometimes we want to add responsibilities to individual objects, as opposed
to an entire class. For example, a graphical user interface toolkit should let you add
behaviours like scrolling and drawing borders to any user interface component.

One way to add responsibilities is with inheritance. Inheriting a border from another class
puts a border around every subclass instance. This leads to inflexibility as the choice of
border is made statically, and a client cannot control how and when to decorate the
component with a border.

A more flexible approach is to enclose the component in another object that adds the
border. The enclosing object is called a decorator. The decorator conforms to the
interface of the component it decorates so that its presence is transparent to the
component’s clients. Transparency permits decorators to be nested recursively, thereby
allowing an unlimited number of added responsibilities.

For example, suppose we have a TextView object that displays text in a window.
TextView has no scroll bars by default, because we might not always need them. When
we do, we can use a ScrollDecorator class to add it. Suppose we also want to add a thick
black border around the TextView. We can use a BorderDecorator class to add this as
well. We simply compose the decorators with the TextView to produce the desired result.

The following class diagram shows how to compose a TextView object with
BorderDecorator and ScrollDecorator objects to produce a bordered, scrollable text view:

VisualComponent is the abstract class (interface) for visual objects. It defines their
drawing and event handling interface. The ScrollDecorator and BorderDecorator classes
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 16 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

are subclasses of the Decorator, an abstract class for visual components that decorate
other visual components. Notice how the Decorator class simply forwards draw requests
to its components, and how the subclasses extend this operation. The Decorator class
maintains a reference to the VisualComponent object and defines an interface that
conforms to the component’s interface. In other words, it has a component object to be
decorated.

Decorator subclasses are free to add operations for specific functionalities. For example,
ScrollDecorator’s scrollTo operation lets other objects add a scrolling functionality to the
interface.

Implementing the Decorator Pattern in code


The following code shows a way of implementing user interface decorators. We start by
creating an interface class:

public interface VisualComponent {


public void draw (); //draws the window
}

The following class is a concrete implementation of this interface. This is the base class
(without any scroll bars or border) on which the decorators will be added.

public class TextView implements VisualComponent {

public void draw () {


// implementation of rendering details
}
}

The abstract Decorator class, the core of the decorator design pattern which wraps
behaviours of subclasses, is then implemented. Notice that this class implements the
VisualComponent class and contains an instance of a visualcomponent object (that is
assigned dynamically at creation using its constructor), as well as methods that the
visualcomponent interface defines. Once assigned, the instance methods can be invoked
(this is called delegation).

https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 17 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

public class Decorator implements VisualComponent {


// private reference to the interface being decorated
private VisualComponent interfaceReference; // the window to be decorated
// Constructor
public Decorator (VisualComponent interfaceReference) {
this.interfaceReference = interfaceReference;
}

public void draw () {


interfaceReference.draw(); // delegation
}

Subclasses of the Decorator define specific decorations. The class ScrollDecorator is a


concrete decorator class that extends abstract Decorator, and defines new behaviour for
the decorator. This class overrides all methods that need to be extended. This concrete
decorator adds a scroll bar functionality:

// concrete Decorator with extended state


public class ScrollDecorator extends Decorator {

// additional state (passing instance of the window to be decorated,


// 'interfaceReference', as an argument)
public ScrollDecorator (VisualComponent interfaceReference) {

super(interfaceReference);
}

public void draw () {


super.draw(); // overrides draw() method in superclass (VisualComponent)
scrollTo();
}

public void scrollTo() {

// draw the scroll bar


}
}

Notice the use of the keyword 'super' above. This is used to access superclass members.
As the draw() method in this subclass overrides the superclasses’s method, you can
invoke the overridden method through the use of this keyword.

The BorderDecorator is another concrete decorator class. Here, a drawBorder() method


https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 18 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

The BorderDecorator is another concrete decorator class. Here, a drawBorder() method


adds functionality to decorate the interface with borders.

// second concrete Decorator with extended state


public class BorderDecorator extends Decorator {

// draw border
}

Finally, we create the text view decorated with scroll bar and border:

public class Window {

// the main() entry method


public static void main (String[] args) {

// instantiating
TextView textView = new TextView();

// decorate TextView with additional behaviours/states (border and scroll bar)


// before putting it in the window
textView = (new BorderDecorator(new ScrollDecorator(textView));
}
}

This creates a text view decorated with scroll bar and border. Notice how the scrolling
and border functionalities have been added dynamically at runtime. This makes it easy to
include decorations as needed.

4.4. Behavioural Patterns


Behavioural patterns identify common patterns of communication and distribution of
responsibilities between classes and objects. This helps in managing complex behaviour.

This session explores:

1. Iterator

2. Observer

3. Template

4. Strategy
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 19 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

4. Strategy

4.4.1. Iterator Pattern


The design goal behind an iterator is to loop through and access elements of a collection
sequentially. This pattern is substantially supported by C# 3.0’s LINQ (Language
INtegrated Query) extensions.

The intent of the Iterator pattern as defined in Design Patterns is to, "Provide a way to
access the elements of an aggregate object sequentially without exposing its underlying
representation."

Implementing the Iterator Pattern in code


A simple example of using an iterator is as follows:

List<String> list = new ArrayList<> ();


list.add ("red");
list.add ("green");
list.add ("blue");

for (Iterator i = list.iterator(); i.hasNext (); ) {


System.out.println ("Item is: " + i.next ());
}

Notice the Iterator object extracted from the list. The Iterator pattern relies on an
interface. The hasNext() method tells us if there are more elements in the aggregate to
iterate through. The next() method returns the next object in the aggregate. Once we
have this interface, we can implement Iterators of various kinds of collections of objects
including arrays, lists, hashmaps etc. All aggregate objects which implement the Iterator
interface provide the same methods, and there is a consistent way to access the
elements within the aggregate.

We shall discuss this pattern further later in the module, when looking at the collections
classes in more detail.

4.4.2. Observer Pattern


The Observer pattern mirrors the publish/subscribe methodology in distributed systems.
This pattern describes a framework in which a specific object (the subject or publisher)
maintains a list of dependents (observers or subscribers) and notifies them of important
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 20 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

maintains a list of dependents (observers or subscribers) and notifies them of important


changes, leading to an abstract coupling between them. The intent of the Observer
pattern as defined in Design Patterns is to, "Define a one-to-many dependency between
objects so that when one object changes state, all its dependents are notified and
updated automatically." When the state of one object changes, its dependents are notified
and updated. This helps in communicating state to a set of objects in a loosely-coupled
manner.

A good example of the Observer pattern is in graphical applications. In a typical graphical


application, we have two parts to the application: a front end "view" and a back end
"model". The "controller" represents the behaviour of the view(s) which can be substituted
with another controller when a different behaviour is needed. The Observer pattern is
implemented in the model and provides an interface which the views and controllers can
use to get and set its state.

Imagine an application storing data from a scientific experiment. There are numbers
about timings and weights and measurements of various kinds. As the experiment runs,
these numbers are constantly being updated. The scientist watching the experiment may
have a graph open showing the different weights against time. They may also have a
table showing the average weight over the last 10 measurements. Other graphs and
charts may present other aspects of the same data. How do we ensure all these graphs
and charts (the views) get updated every time a new measurement comes in?

The solution is the Observer design pattern, which is a way to register certain observing
classes with an observable class: in our example, the stored data from the
measurements would be held in an observable class, and the different graphs and charts
would be different observing classes. The idea is quite simple: as the observed class
changes, it tells all its observers to update themselves.

How does this work? First, there is an initialisation stage:

1. As part of the initialisation, Views (Observer) register with the Model (Subject)

2. Registration involves each View passing a reference to itself …

3. … which the Model stores in a List

4. Apart from this, and the fact that each View implements the Observer interface, the
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 21 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

4. Apart from this, and the fact that each View implements the Observer interface, the
Model knows nothing about the details of the Views.

5. Each View keeps a reference to the Model

6. This two-way dependency is used in a call back.

The following is a general class diagram for the Observer pattern. Subjects (observables)
update Observers using a common interface. They define a one-to-many relationship:

When changes happen, the following sequence of events occurs:

1. When the Model is updated by its Controller class, the Model broadcasts a notification
that it has changed to each registered View, by calling their update method, through
notifyObservers.

2. update in each View calls back to retrieve the Model’s state ("pull" implementation)

3. Views then modify their rendering of Model.

The Observer pattern can be implemented in two ways, depending on how we wish to
deal with a change in the model: we can either send ("push") data out to the views and let
them process the data, or we can tell the views that we have changed, and lets them
interrogate the appropriate methods of the model ("pull").

The latter technique means that the model can be developed independently of the view.
The view is then developed based around the methods that the model exposes. The
Observer pattern ensures loose coupling by providing an object design in which the
objects can interact but have very little knowledge of each other.

Implementing the Observer Pattern in code


https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 22 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

Implementing the Observer Pattern in code


Java supports the Observer pattern with an existing interface and class. The following
code creates a simple Model class. Notice the following:

1. the class extends java.util.Observable

2. whenever something changes in the model, setChanged() is called

3. when required, notifyObservers() will tell all registered observers to update


themselves

package observerexample;

import java.util.List;
import java.util.ArrayList;

public class Model extends java.util.Observable { // subclassing Observable


private List<String> values;

public Model () {
values = new ArrayList<String> ();
}

// called by Controller to add a value


public void addValue (String string) {
values.add (string);

// call the following method first to indicate the state has changed
setChanged ();
// before calling notifyObservers()
notifyObservers (); // model has changed, so let observers know. (1)
}

// called by Controller to clear all values


public void clear () {
values.clear();

setChanged ();
notifyObservers (); // model has changed, so let observers know
}

public int getSize () {


return values.size ();
}

public String getValue (int index) {


return values.get(index);
}

https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 23 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

}
}

1. Notice that in this case, the Observer has to "pull" the data it needs from the
Observable object. If you want to "push" data to the observers, you can pass the data
as argument to this method.

The following code creates an Observer object. To be an observer, the object must
implement the update method. This gets called when the model calls notifyObservers. To
implement the "pull" technique, the view is created with a reference to the observed
Model. This enables the view to update its display or print out information by interrogating
the object directly.

package observerexample;

public class View1 implements java.util.Observer {


private Model model;
private String name;

public View1 (Model model, String name) {

this.model = model;
this.name = name;
}

public void update (java.util.Observable obs, Object obj) {


System.out.println ("Updating View 1: " + name);
System.out.println ("Model now has " + model.getSize () + " items");
for (int i = 0; i < model.getSize (); ++i) {
System.out.println ("Object " + i + " is " + model.getValue(i));
}
}
}

Finally, the following Main class shows how a model can be created and observers added
and removed at will. Notice that addObserver and deleteObserver are implemented by
the Observable superclass.

package observerexample;

import java.util.*;

public class Main {

https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 24 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

public static void main(String[] args) {


Model model = new Model ();
System.out.println ("Adding value: abc");
model.addValue ("abc");

// create and add an observer


Observer observer1 = new View1 (model, "first view");
model.addObserver(observer1);

System.out.println("Adding value: def");


model.addValue ("def");

// create and add a second observer


Observer observer2 = new View1 (model, "second view");
model.addObserver(observer2);

System.out.println("Clearing all values");


model.clear ();

System.out.println("Adding value: def");


model.addValue ("def");

// remove first observer


model.deleteObserver(observer1);

System.out.println ("Adding value: abc");


model.addValue ("abc");

}
}

Make sure you run the code above and understand the different stages in the
addition/deletion of observers.

As you have seen above, using Java’s built-in Observer pattern (the Observer interface
and the Observable class in the java.util package), you can extend the Observable class
to tell it when to notify the Observers. The API handles the rest.

In spite of providing some utility through out-of-the-box functionality, the


java.util.Observable has a few issues that limit its usefulness and flexibility. One of this is
that it violates the good design principle of "programming to interfaces, not
implementations". This stems from the fact that Observable in this case is neither an
interface itself (it is a class, as can be seen in the code above) nor does it 'implement' an
interface (it 'extends' the Observer interface). For an alternative, and to see how this
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 25 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

interface (it 'extends' the Observer interface). For an alternative, and to see how this
issue can be addressed, refer to pgs. 57-60 of Head First Design Patterns.

The next two patterns, Template Method and Strategy, are similar in that they allow
different implementations for a fixed set of behaviours. However, while the focus of
Template is to enforce consistency, the focus of Strategy is to allow variety.

4.4.3. Template Method Pattern


The Template Method pattern creates a template (or method) that defines an algorithm as
a set of steps, where some steps are kept abstract and left to the concrete subclasses to
implement. The intent of the Template Method pattern as defined in Design Patterns is to,
"Define the skeleton of an algorithm in an operation, deferring some steps to subclasses."
By deferring some steps in a complex algorithm to subclasses, subclasses are able to
provide specific behaviour without affecting an algorithm’s overall design.

The problem that this pattern addresses is when mostly the same sequence of steps is
performed but some parts need specialising. As an example, consider outputting the text
for a report. This may sometimes need to be outputted as plain text, sometimes in HTML,
sometimes in PDF, etc. However, in all cases, the same header or a particular section of
the body will be output.

Implementing the Template Method Pattern in code


We begin the design of the Template pattern with an abstract class. This class provides
the core algorithm, using separate methods for the steps in the algorithm. These separate
methods are abstract, and must be supplied in subclasses: these abstract methods are
called hook methods.

// abstract class
public abstract class ReportWriter {
private String title; // (1)
private String[] text; // (2)

public void outputReport () { // (3)


outputStart (); // (4)
outputHead ();
outputBodyStart ();
outputBody ();
outputBodyEnd ();
outputEnd ();
}
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 26 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

// concrete subclass
public void outputBody () { // (5)
for (String line : text) {
outputLine (line);
}
}
public abstract void outputStart ();
public abstract void outputHead ();
public abstract void outputBodyStart ();
public abstract void outputBodyEnd ();
public abstract void outputEnd ();
public abstract void outputLine ();
}

1. The title holds the title of the report.

2. The text holds the body of the report.

3. outputReport implements the core algorithm, and is the template method.

4. Each step of the algorithm is implemented (in the subclass) as a separate method.
Besides these, any method(s) specific to a subclass are declared abstract.

5. We provide an implementation of outputBody which calls out to another abstract


method, outputLine.

A subclass to print a html report might look as follows:

public HtmlReportWriter extends ReportWriter {


public void outputStart () {
System.out.println ("<html>");
}
public void outputHead () {
System.out.println (" <head>")
System.out.println (" <title>" + title + "</title>");
System.out.println (" </head>")
}
public void outputBodyStart () {
System.out.println ("<body>")
}
public void outputLine (String line) {
System.out.println ("<p>" + line + "</p>");
}
public void outputBodyEnd () {
System.out.println ("</body>")
}
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 27 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

}
public void outputEnd () {
System.out.println ("</html>");
}
}

Notice how the concrete class simply implements each of the hook methods in turn. The
concrete class has no knowledge of the underlying algorithm or order in which these
methods will be called. This enables creating new implementations for a general
algorithm (this is placed in the base class).

The Template Method pattern is sometimes used to implement hooks in a system, such
as an application framework (discussed in the next session).

The general Template pattern looks as follows:

The AbstractClass (as seen in class diagram above) contains the template method. The
PrimitiveOperations in this class are abstract versions of the operations that are
decoupled form the actual implementation (concrete operations). There may be several
ConcreteClasses that implement the abstract operations, which are called when the
TemplateMethod() needs them.

The AbstractClass contains abstract methods for the primitive operations, which act as
hooks for the concrete classes to fill out.

This pattern gives us an important technique for code reuse. You can see many
examples of its use in real-world code.

While this pattern is easy to understand, it is easy to overlook in practice. The same
applies for the Strategy pattern, which we will explore next. Also, the Template Method

https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 28 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

and the Strategy patterns both encapsulate algorithms; the first one by inheritance and
the second one by composition. The Factory Method (which is discussed briefly in
session 2) is a specialisation of the Template Method.

4.4.4. Strategy Pattern


The Strategy pattern provides a flexible alternative to subclassing. Like the Template
Method, it deals with generalising algorithms. However, in this case the focus is on
selecting a particular algorithm at runtime, instead of algorithms extending a general
template. When many related classes differ only in their behaviour, this pattern provides a
way to configure them with one of many behaviours. This enables addressing the issue of
inflexibility of the Template Method (which relies on inheritance to define the behaviour of
a class) by allowing changing the behaviour by using a different object.

The intent of the Strategy pattern as defined in Design Patterns is to, "Define a family of
algorithms, encapsulate each one, and make them interchangeable." It allows the
algorithm to vary independently, as the clients request.

An example might be a program for playing music: the music may be in different formats,
MP3, WAV, Midi files, etc. The music program needs to operate in the same way, no
matter which algorithm it is using to interpret the music format.

The solution is to encapsulate the algorithm in an object. Different classes provide the
different implementations. In Java, we make each class implement the same interface.

client code is then written in terms of the interface, rather than a concrete class
implementation

client is decoupled from the class that provides it with the service

service provider can be replaced by a different one without any effect on the client
code.

This pattern has become a pervasive style of doing object-oriented development: often
known by the phrase "Program to an interface, not an implementation", that we have
discussed in the previous unit.

https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 29 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

The figure above illustrates the design behind the Strategy pattern. The code below
shows a sketch of the code for the music example. Notice how the different classes
implementing the AudioPlayer interface have no other connection as classes. However,
by implementing the same interface, they can all be plugged into the MusicPlayer:

Implementing the Strategy Pattern in code

public interface AudioPlayer {


public void play (File f);
}

public class Mp3Player implements AudioPlayer {


}

public class MidiPlayer implements AudioPlayer {


}

public class MusicPlayer {


private AudioPlayer player; // store here a concrete class implementing AudioP
layer

public void playing (File f) {


// at some point, call the play method of player
player.play (f);
}
}

This concludes the tour of the Creational, Structural, and Behavioural design patterns.
The patterns discussed here ultimately deal with abstracting concepts and algorithms into
classes and objects. While patterns provide an elegant way of designing applications, be
cautious of their overuse.

4.5. Frameworks

https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 30 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

Having explored concept reuse using design patterns in the previous sessions, this
session looks at design reuse using frameworks, which are generic structures that can be
extended to create a more specific sub-system or application. Frameworks enable object
reuse in an object-oriented development process through larger-grained abstractions.

A framework can be defined as an integrated set of collaborating software artefacts


(classes, objects and components) that provides a reusable architecture (generic
features) common to a family of applications of a similar type. For e.g., a user interface
framework provide support for interface event handling through a set of widgets that can
be used to construct displays (layouts).

Frameworks support design reuse by providing a skeletal architecture that is


implemented by a collection of concrete and abstract object classes and their
interactions. Classes may be reused directly or be extended using features such as
inheritance and polymorphism. To adapt and extend the framework you need to add
concrete classes that inherit operations from the provided abstract classes. In addition,
you need to define "callbacks" to invoke "hook methods" (discussed in the context of the
Template Method pattern) recognised by the framework in response to events from the
user interface. These methods are then linked to the user-provided functionality
appropriate to the subsystem or application being implemented.

Frameworks are language-specific and implemented as a collection of concrete and


abstract object classes in object-oriented programming languages (Java, C# and C++)
and dynamic languages (Ruby and Python). A single framework can facilitate the creation
of a complete application or it can incorporate several frameworks, with each supporting
the development of a specific part of an application (e.g., GUI).

Frameworks can be classified into (Sommerville, Software Engineering):

System infrastructure frameworks


support the development of system infrastructure such as user interfaces, compilers,
etc.

Middleware integration frameworks


provide standardised component models and support component communication and
information exchange. Examples include Microsoft’s .NET and Enterprise Java Beans
https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 31 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

information exchange. Examples include Microsoft’s .NET and Enterprise Java Beans
(EJB).

Enterprise application frameworks


concerned with specific application domains such as financial systems. They embed
application domain knowledge and support the development of end-user applications.
However, they have now been superseded by software product lines.

The most widely-used application frameworks are Web Application Frameworks (WAFs)
that facilitate the construction of dynamic website by providing components and classes
that support dynamic web pages, database integration, user interaction, session
management, etc. The architecture of a WAF is normally based on the Model View
Controller (MVC) Compound pattern (a pattern of patterns), which was originally
proposed as an approach to GUI design. In essence, MVC separates the state from its
presentation. This description might help you to relate it to the Observer pattern
discussed in session 4. An example is Swing, which, like many GUI frameworks, makes
use of the Observer pattern.

As is evident, frameworks are often implementations of several design patterns whose


abstract and concrete classes allow for extensibility. Design Patterns and Frameworks
share some similarities. However, they differ in the following ways:

Frameworks are less abstract than Design Patterns


while Frameworks are embodied in code, only examples of patterns can be embodied
in code. A strength of frameworks is that they can be written down in concrete
programming languages and executed and reused directly. In contrast, design patterns
must be implemented in code each time they are used.

Frameworks are larger architectural elements than Design Patterns


a typical framework may consist of several design patterns, but the reverse is not true.

Frameworks are more specialised than Design Patterns


frameworks are specific to an application domain. In contrast, design patterns can be
used in several kinds of applications. Also, unlike frameworks, design patterns do not
dictate an application architecture.

https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 32 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

The fundamental problem with frameworks is their inherent complexity and steep learning
curve. Besides, although they are an effective approach to reuse, they result in "inversion
of control" between the application and the framework on which it is based. A framework
restricts operation names and calls, necessitating their conformance to the specified
conventions. This can impose a constraint on design decisions.

4.6. Exercises

Exercise 1
Identify the Design Patterns from the following descriptions:

1. Clients treat collections of objects and individual objects uniformly.

2. Provides a way to traverse a collection of objects without exposing the collection’s


implementation

3. Allows a group of objects to be notified when some state changes

4. Encapsulates interchangeable behaviours and uses delegation to decide which one


to use.

5. Subclasses decide how to implement steps in an algorithm.

6. Wraps another object and provides additional behaviour for it.

Exercise 2
Using the Singleton pattern, design an incremental counter with two methods: one
method that increments the count, and the other that displays the latest count (up to 10).

Exercise 3
Session 2 of this unit discusses the Factory pattern, including the Factory Method. Your
task is to explore the other variation, Abstract Factory, and share a brief review on its
Intent and the feature that distinguishes it from the Factory Method. Share your review on
the discussion forum in StudyNet.

https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 33 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

Exercise 4
(QUESTION DELETED)

Exercise 5
Model View Controller (MVC), mentioned in session 5, is considered as a set of patterns
working together in the same design. Which 3 patterns discussed here are used in the
MVC framework? What are their roles in the framework?

Exercise 6
It is often observed that overuse or unnecessary use of design patterns can be counter-
productive. What are the downsides of using Design Patterns? Think for yourself about
some of the potential problems, try some searching for similar or opposing views in
published books/papers, and try to come to a conclusion. Share your ideas on the
StudyNet discussion forum.

Exercise 7
Imagine writing a program to model someone cooking a recipe. There are basic tasks,
such as beating an egg, taking a quantity of flour. Then more complex tasks, such as
making batter, rely on the more basic tasks. Making a cake might rely on making a batter,
preparing a cake tin, etc. Which design pattern or patterns would help organise this
program? Sketch out some sample classes in code or UML to capture the design.

Exercise 8
The following diagram illustrates the layout of the InputStream libraries within the Java
API. Explain how these implement the Decorator design pattern, and provide some
example code illustrating the wrapping process. How is the Template pattern used?

https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 34 of 35
Design Patterns and Frameworks: 6WCM0027-0105-2021 - Programming & Software Engineering Practice (COM) 25/04/2022, 4:03 PM

https://herts.instructure.com/courses/92276/pages/design-patterns-and-frameworks?module_item_id=1778082 Page 35 of 35

You might also like