2025-10-02
Designing software is hard, designing reusable and flexible software is even harder
Design Patterns – an attempt to build on others’ experience in solving recurrent problems
Contrast with architectural style: implications for many modules
Each pattern describes a problem that occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice” – Christopher Alexander, A Pattern Language
Has four essential elements:
It is a class that apparently cannot be instantiated! But that’s not really true…
It is a vanilla static method… But combined together with the previous, it gives us…
The Singleton Pattern ensures a class has only one instance, and provides a global point of access to it.
The getInstance() method is static therefore you can conveniently access this method anywhere in your code using Singleton.getInstance().
The uniqueInstance class variable holds our one and only instance of Singleton.
That’s just as easy as accessing a global variable, but we get benefits like lazy instantiation from the Singleton.
Any potential problems with this approach?
Explain why design patterns are useful and some caveats to consider when using design patterns
Clearly and concisely describe, give examples of software situations in which you’d use, explain the key benefit of, and drawbacks or special considerations for the following patterns:
In software engineering, a design pattern is a general repeatable solution to a commonly occurring problem in software design.
Solution: P-trap
Solution: cloverleaf
Name: Observer
Intent: Ensure that, when an object changes state, all its dependents are notified and updated automatically.
Participants & Structure: 
I need the professor to be notified when a student joins his/her class
I want the display to update when the size of a window is changed
I need the schedule view to update when the database is changed
Design patterns are reusable!
Use a GenAI tool to create a Python solution to a newsletter service needing to maintain a list of subscribers. Use the Observer pattern.
Once you have some sample code, try to see where you might run into maintainability challenges in the future.
‘+’ decouple observer and observable (also known as “publisher/subscriber” or pub-sub)
‘+’ observable/publisher only knows what is listening, not what they do
‘+’ can observe many publishers
‘-’ implicit flow of control means hard to debug
‘-’ list of observers can be unwieldy (FB social graph)
‘-’ questions about how/when/where updates arrive.
Part “Craft”
Part “Art”
Part “Science”
The pattern sometimes convey a lot of information Try understanding this code: 
Key is to know the Abstract Factory and Decorator patterns!
Dev 1: “I made a Broadcast class. It keeps track of all of its listeners and anytime it has new data it sends a message to each listener. The listeners can join the Broadcast at any time or remove themselves from the Broadcast. It’s really dynamic and loosely-coupled!”
Dev 2: “Why didn’t you just say you were using the Observer pattern?”
Makes a system independent of how its objects are created
Useful as system evolves: the classes that will be used in the future may not be known now
Techniques to compose objects to form larger structures
Concerned with communication between objects
Describe complex control flow
Problem context:
Build a maze for a computer game
A maze is a set of rooms
A room knows its neighbours: room, door, wall
Ignore players, movement, etc.
See example MazeGame.java
Sample Problem: Your game needs to create rooms, but you are not quite sure yet how these rooms will be implemented and you think they will be extended in the future.
Solution 1:
Problem? (any design principle violated?)
Solution 2:
Advantage: Just set myRoomFactory once, then the good room will be created!
Remark: Setting myRoomFactory is Dependency Injection: the class which is dependant on myRoomFactory doesn’t retrieve it, but waits until someone else injects it.
‘+’ control creation of costly concrete classes
‘+’ easy to change factories
‘-’ hard to extend factories
Name: Abstract Factory
Intent: Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
Participants & Structure:
You need to implement a point-of-sale system for a coffee shop. The coffee shop has some basic beverages, but customers can customize their drinks by choosing what kind of milk they want, if they want flavoured syrup, etc.
You could create a class for each drink, but there are so many possible combinations that the number of classes would quickly get out of hand.
Name: Decorator
Intent: Attach additional responsibilities to an object dynamically
Participants & Structure:
src: Head First Design Patterns
Mediator is a behavioral DP that is useful when many objects communicate with one another.
Mediator redirects communication through itself instead (think about this in terms of coupling and cohesion)
Unlike Observer, connections are many to many through the Mediator.
The mediator can do things like prioritize, scale, analyze the messages.
Enterprise Service Buses (ESBs) and Message Queues (RabbitMQ) are flavours of Mediator.
A message bus is a way to direct communications between components via a centralized messaging object. In our example, we will have Services dynamically register to our Mediator, and different Services respond to Events from the Mediator.
In particular, think about the scenario where users register for our recipe website. Our website will have an AccountService and EmailService. When the user registers, an Event is sent to the Mediator (“UserRegistered”). The Mediator then publishes this event to registered Services.
Each Service then has logic (not specified) to take action on a given event type (e.g., send a welcome email).
(homework?) instantiate your solution in Python/Java/C++. ## Here is the implementation for the Mediator DP.
via https://refactoring.guru/design-patterns/mediator

Neil Ernst ©️ 2024-5