Lecture recording here.
Lab recording here.
We start our study of behavioural patterns. The observer pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. The strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
| The Observer Design Pattern | Observer Design Pattern |
| The Observer Pattern Explained and Implemented in Java | |
| The Strategy Design Pattern | What is the Strategy Pattern? (Software Design Patterns) |
| The Strategy Pattern Explained and Implemented in Java |
Assignment 3 - Investigation of Design Patterns
The Rationale
The Observer software design pattern is used when you want to establish a one-to-many relationship between objects, so that when one object changes state, all its dependents are notified and updated automatically. The observer design pattern promotes loose coupling between objects, which means that the objects don't have to know much about each other, and can be easily modified without affecting other parts of the system.
By using the Observer pattern, the subject object (the one that is being observed) and the observer objects (the ones that are notified of changes) can be developed and tested independently of each other. This makes the code easier to maintain, extend, and reuse. Another benefit of this pattern is that it allows for more flexibility in designing systems, as it enables the dynamic addition and removal of observers at runtime. This means that new functionalities can be easily added without changing the core code, and unwanted functionality can be removed without affecting the rest of the system.
The UML
Here is the UML diagram for the Observer pattern:

Here are the components of the Observer design pattern:
Code Example - Observer
In the following code example, the class Subject is used to add and remove observers, as well as notify them.
The class Observer is the abstract class that is the base class for ConcreteObserver:
C++: Observer.cpp.
C#: Observer.cs.
Java: ObserverMain.java.
Python: Python.py.
Common Usage
The following are some common usages of the observer pattern:
Code Problem - Random Number Generator
We have code that implements several types of random numbers. The number of random numbers is not known at compile time. The user will
be prompted for the number of random numbers. Once this has been received, all random number generators have to be notified.
The following example generates a series of low and high definition random numbers. A thread receives user input for how many random numbers
should be generated. Once the input is received, all registered objects are notified, each generating a number of random numbers:
Observer.h, the abstract base class for all kinds of observers,
LowDefinitionObserver.h, a concrete observer,
HighDefinitionObserver.h, a concrete observer,
Subject.h, abstract class for all kinds of subjects (not necessary),
IntegerSubject.h, a concrete subject,
RandomNumber.cpp, the main function.
Code Problem - Library Statistics
The following code adds book and DVD items to a library. A book observer and DVD observer keep track of the number of book and DVDs
respectively and their types. So, each time an item is added to the library, an update function is called in the observers to update
statistics. The observers can also print statistics. For instance the book observer prints how many books and also the percentages of
each type of book. Likewise the DVD observer prints how many DVDs and the percentage of each type of DVD. The code can be seen below.
Observer.h, the abstract class for all observers,
BookObserver.h, the concrete book observer,
DVDObserver.h, the concrete DVD observer,
Item.h, an interface class for all subjects (a library item),
Book.h, the book concrete subject,
DVD.h, the DVD concrete subject,
Library.h, the library,
LibraryMain.cpp, the main function.
The Rationale
The Strategy software design pattern is used to define a family of algorithms, encapsulate each one, and make them interchangeable. This pattern therefore provides a flexible way to switch between different algorithms or behaviors at runtime, without changing the overall structure of the system.
By using the Strategy pattern, you can separate the implementation of an algorithm from its context, which makes the code more modular, easier to understand, and easier to maintain. This also promotes the Open/Closed principle, which states that software entities should be open for extension but closed for modification. Another benefit of this pattern is that it enables better code reuse, as you can create a library of interchangeable algorithms that can be used across multiple projects or applications.
The UML
Here is the UML diagram for the ... pattern:

Here are the components of the Observer design pattern:
Code Example - Concrete Strategy
In this example, the class Context sets and executes a concrete strategy. The class Strategy is the
interface class from which ConcreteStrategyA and ConcreteStrategyB are derived:
C++: Strategy.cpp.
C#: Strategy.cs.
Java: StrategyMain.java.
Python: Strategy.py.
Common Usage
The following are some common usages of the strategy pattern:
Code Problem - Sorting Strategy
The Standard Template Library provides us with a few sorting algorithms. Which algorithm we use depends on what we want
sorted. The following code uses one of three sorting strategies. Each strategy is based on an STL algorithm:
SortingStrategy.h, abstract base class for sorting strategies,
StdSortStrategy.h, concrete sorting strategy using STL::sort,
StdStableSortStrategy.h, concrete sorting strategy using STL::stable_sort,
StdPartialSortStrategy.h, concrete sorting strategy using STL::partial_sort,
Sorter.h, context that uses a sorting strategy to sort data,
SorterMain.cpp, main function for sorting.
Code Problem - Custom Sorting Strategy
The following code performs sorting without using STL's sorting algorithm. The bubble sort and quick sort algorithms
are coded.
SortingStrategy.h, abstract base class for sorting strategies,
BubbleSort.h, the bubble sort concrete class,
QuickSort.h, the quick sort concrete class,
Sorter.h, context for sorting data,
SortMain.cpp, the main function for the sorter.
Code Problem - Combined Sorting Strategy
Since the interfaces used in the above two examples are the same, it is quite easy
to add the sorting strategies QuickSort and BubbleSort to the strategies of the first example:
SortingStrategy.h, abstract base class for sorting strategies,
BubbleSort.h, concrete sorting strategy using BubbleSort,
QuickSort.h, concrete sorting strategy using QuickSort,
StdSortStrategy.h, concrete sorting strategy using STL::sort,
StdStableSortStrategy.h, concrete sorting strategy using STL::stable_sort,
StdPartialSortStrategy.h, concrete sorting strategy using STL::partial_sort,
Sorter.h, context that uses a sorting strategy to sort data,
SorterMain.cpp, main function for sorting.
Software developers typically build streaming applications using multimedia streaming frameworks like DirectShow, GStreamer, and Symbian MMF. Although a significant amount of work has been done on architectural and design patterns in software engineering, there is a limited notion of patterns in the development of multimedia streaming software.
Since it is costly and time-consuming to build multimedia streaming software from scratch, multimedia frameworks enable streaming applications to be assembled by integrating pluggable media components. In addition, multimedia frameworks isolate applications from a variety of complex tasks such as handling of the complex multimedia acceleration hardware, data transport, and synchronization between various tasks.
One of the broadly recognized approaches in the development of the multimedia streaming software is to structure the streaming software as Pipes and Filters. The Pipes and Filters architectural pattern divides a complex functionality into several sequential processing subfunctionalities forming a streaming graph.
An activity diagram for the pipes and filters pattern is shown below:
The following is an example of the Pipes and Filters pattern:
Filter.h,
DoubleFilter.h,
EvenFilter.h,
SumFilter.h,
Pipe.h and
PipesAndFilters.cpp.
If you look at the code carefully, you will see this to be a variation of the observer pattern.
An article on design patterns for multimedia can be seen at Architectural and Design Patterns in Multimedia Streaming Software, Dajsuren and van den Brand, 2014.
Event-driven architecture is a model of software design that uses the flow of events through a system to drive the system's responses. Request/response systems - the traditional form of software architecture - instead require application components to request updates and wait for a response. In many contexts, request/response systems work well enough. But when enterprises require greater scalability, resiliency, or usage of realtime data, event-driven architecture can offer an outsized advantage over other architecture designs.
See Event-driven architecture patterns and when to use them for more details.
We will look at the publish/subscribe pattern. In the Publish/Subscribe pattern, publishers and subscribers are decoupled, and communication between the two is asynchronous. Publisher and subscriber components are separated and a broker facilitates the processing of events and the passing of events from publishers to subscribers in realtime.
Key to the Publish/Subscribe pattern is the shift of architectural complexity from client to publisher. With a Pub/Sub pattern, even complex applications can become as smooth and seamless as smaller, simpler applications. The shift of complexity means the client isn't stuck polling and waiting and polling again. Events drive processes and with brokers handling message routing, components are free to keep running to support the larger application.
Below is a simple implementation of the publish/subscribe design pattern
in C++. As you can see, this is effectively the observer design pattern once again.
PubSub.cpp.
A more complex example of the publish/subscribe design pattern is given
below. In this example, the mouse subscriber subscribes to mouse events and
the key subscriber to key events. This is also a variation of the observer
design pattern:
Event.h,
KeyEvent.h,
MouseEvent.h,
EventManager.h,
Subscriber.h,
KeySubscriber.h,
MouseSubscriber.h,
MouseKeyMain.cpp.