Software Design Review
Software Design Review
Contents
1 Design Patterns Overview 3
1.1 Course Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.1 Why Use Design Principles & Patterns? . . . . . . . . . . . . . . . . . . . . . 3
1.1.2 OOP Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.3 Object-Oriented Design Principles . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.4 Encapsulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.5 Abstraction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.6 Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.7 Polymorphism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Design Principles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.2 SOLID Principles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.3 Other Design Principles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.4 Additional Design Principles . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.5 What is a Class? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.6 Grady Booch’s Quality Metrics . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.7 UML Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2 Creational Patterns 8
2.1 Strategy Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.2 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1.3 Problems with Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1.4 Alternatives Considered . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1.5 Solution: Strategy Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1.6 Key Design Principle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1.7 Implementation Details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1.8 Duck Simulation Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.1.9 Composition vs Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.1.10 Real-World Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2 Lecture 04: Observer Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2.2 Weather Monitoring System Example . . . . . . . . . . . . . . . . . . . . . . 11
2.2.3 Initial Design Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2.4 Observer Pattern Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2.5 Implementation Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2.6 Push vs Pull Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1
2.2.7 Java Built-in Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.8 Real-World Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.3 Lecture 05: Decorator Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.3.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.3.2 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.3.3 Example: Starbuzz Coffee . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.3.4 How Decorators Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.3.5 Key Participants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.3.6 Decorator vs Strategy Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.3.7 Real-World Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.4 Lecture 06: Factory Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4.2 Types of Factory Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4.3 Simple Factory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4.4 Factory Method Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4.5 Abstract Factory Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4.6 Key Benefits Comparison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4.7 Use Cases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.5 Lecture 07: Singleton Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.5.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.5.2 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.5.3 Implementation Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.5.4 Singleton vs Static Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.5.5 Multithreading Concerns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.5.6 Singleton Variations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.5.7 Drawbacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3 Behavioural Patterns 18
3.1 Lecture 08: Command Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.1.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.1.2 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.1.3 Example: Smart Home Remote Control . . . . . . . . . . . . . . . . . . . . . 18
3.1.4 Key Participants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.1.5 Benefits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.1.6 Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.2 Lecture 09: Adapter & Facade Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.2.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.2.2 Adapter Pattern Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.2.3 Adapter Pattern Participants . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.2.4 Adapter Use Cases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.2.5 Facade Pattern Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.2.6 Facade Pattern Participants . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.2.7 Home Theater Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.2.8 Adapter vs Facade Comparison . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2.9 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1 Design Patterns Overview
This course focuses on Software Design, particularly Object-Oriented (OO) Design. It covers
three main areas:
1. OO Design Principles - Guidelines for creating better software
2. Design Patterns - Reusable solutions for common software problems
3. Software Architecture - High-level organization of software systems
1.1.4 Encapsulation
• Restricts access to internal object details
• Reduces dependencies between components
• Example: Make fields private and expose them through public methods
1.1.5 Abstraction
• Hides complexity by providing a simplified interface
• Abstract Classes vs. Interfaces:
– Interface: Defines behavior but no implementation
3
– Abstract Class: Can define some default behaviors
1.1.6 Inheritance
• ”Is-a” relationship: One class inherits behavior from another
• Used for code reuse, but can lead to tight coupling
• Benefits:
– Code reuse through hierarchical relationships
– Establishes type relationships
• Drawbacks:
– Can create rigid hierarchies
– May violate LSP if not careful
– Increases coupling between classes
1.1.7 Polymorphism
• Same interface, different implementations
• Types of Polymorphism:
– Runtime (Dynamic) - Method overriding
– Compile-time (Static) - Method overloading
• Benefits:
– Flexibility in design
– Supports ”programming to interfaces”
– Enables loose coupling
1.2.1 Overview
Object-Oriented (OO) Design Principles provide guidelines for writing clean, maintainable,
and flexible software.
• Design Patterns are built on these principles
• Without understanding these principles, design patterns may not be fully understood
4
• Example: Instead of modifying a class every time a new shape is introduced, use an
abstract shape interface
• New shapes can be added by implementing the interface, without changing existing code
3. Liskov Substitution Principle (LSP)
• Subtypes must be replaceable with their base types without breaking the program
• A derived class should not alter the expected behavior of its base class
• Example Problem: A Square subclass of Rectangle violates LSP
• Setting one side of a square affects both width and height, breaking expectations
• Solution:
– Make the Rectangle immutable
– Remove the inheritance relationship
– Define Square separately
4. Interface Segregation Principle (ISP)
• Prefer many small interfaces over a single large interface
• A class should not be forced to implement methods it does not use
• Example: If a Worker interface includes takeBreak(), it’s inappropriate for robot work-
ers
• Solution: Split into smaller interfaces (Workable, Breakable)
5. Dependency Inversion Principle (DIP)
• High-level modules should not depend on low-level modules
• Both should depend on abstractions
• Abstractions should not depend on details
• Details should depend on abstractions
• Example: A Copy module should depend on abstract interfaces:
– Reader interface instead of KeyboardReader
– Writer interface instead of PrinterWriter
5
4. Principle of Least Knowledge (Law of Demeter)
• Objects should interact only with closely related objects
• Only talk to your immediate friends
• Avoid method chaining: a.getB().getC().doSomething()
• Instead delegate through appropriate objects
• Benefits:
– Reduces dependencies
– Makes code more maintainable
– Easier to modify individual components
5. Hollywood Principle
• ”Don’t call us, we’ll call you”
• Low-level components can hook into high-level components
• But high-level components control when to call them
• Examples:
– Template Method Pattern
– Observer Pattern
– Dependency Injection frameworks
6
1.2.6 Grady Booch’s Quality Metrics
• Coupling:
– Minimize interdependencies between classes
– Fewer connections mean easier maintenance
– Changes in one class affect fewer other classes
• Cohesion:
– Keep related data and behaviors together
– Each class should have a single, well-defined purpose
– Methods should work together to serve class’s purpose
• Sufficiency:
– Capture enough details to be useful
– Include all necessary operations
– Balance between completeness and simplicity
• Completeness:
– Include all necessary behavior
– Public interface should provide all needed functionality
– No missing operations that clients need
• Primitiveness:
– Avoid unnecessary methods
– Each operation should be atomic and fundamental
– Don’t include operations that can be composed from others
7
Figure 1: UML Relationship Types
Type Description
Association One class uses another (→)
Inheritance Subclass extends superclass (▷)
Realization/Implementation Class implements interface (99K ▷)
Dependency Loosely defined relationship (99K)
Aggregation Weak ”has-a” relationship (♢)
Composition Strong ”has-a” relationship (♦)
2 Creational Patterns
2.1.1 Overview
8
2.1.2 Motivation
Using Interfaces:
• Introduced Flyable and Quackable interfaces
• Problems:
– Each class must provide its own fly() and quack() method
– No code reuse – changes must be updated in multiple places
– Doesn’t allow for easy runtime behavior changes
Java 8 Default Methods:
• Provides reusable implementations in interfaces
• Helps prevent breaking existing implementations
• Limitations:
– Cannot maintain object state
– Unsuitable for strategy-based behaviors
9
– FlyBehavior
– QuackBehavior
• Behavior Classes:
– FlyWithWings
– FlyNoWay
– Quack
– Squeak
– MuteQuack
• Delegate behaviors to strategy objects instead of defining in Duck
10
– Different behaviors for NPCs
• Data Storage:
– Database vs cloud vs local file
– Strategy selected based on requirements
2.2.1 Overview
Requirements:
• Weather Station monitors:
– Humidity
– Temperature
– Barometric pressure
• Display types:
– Current Conditions Display
– Weather Statistics Display
– Forecast Display
• Support for future extensions
Key Participants:
1. Subject (Observable):
• Maintains observer list
• Notifies on data changes
• Methods:
registerObserver(Observer o)
removeObserver(Observer o)
notifyObservers()
2. Observers:
11
• Register with subject
• Receive automatic updates
• Method: update(data)
12
• Example:
update()
float temp = subject.getTemperature();
2.3.1 Overview
2.3.2 Motivation
13
2.3.3 Example: Starbuzz Coffee
Role Description
Component Defines interface for objects that can be decorated
ConcreteComponent Base object to which decorators are added
Decorator Maintains reference to Component and matches interface
ConcreteDecorator Extends functionality by modifying/adding behavior
Decorator Strategy
Changes external behavior Changes internal logic
Stacks multiple behaviors Replaces entire behaviors
14
2.4 Lecture 06: Factory Patterns
2.4.1 Overview
Factory Patterns:
• Handle object creation while hiding instantiation logic
• Decouple object creation from application logic
15
2.4.7 Use Cases
• Database Connections:
– Different drivers (MySQL, PostgreSQL)
• UI Frameworks:
– Platform-specific UI elements
• Dependency Injection:
– Decoupling instantiation from business logic
2.5.1 Overview
2.5.2 Motivation
16
– Eager initialization (startup creation)
– Double-checked locking (balanced approach)
– Volatile keyword (memory visibility)
2. Eager Initialization:
3. Thread-Safe Singleton:
4. Double-Checked Locking:
5. Enum Singleton:
17
public enum Singleton {
INSTANCE;
public void doWork() {
// singleton behavior
}
}
2.5.7 Drawbacks
• Global State Issues:
– Similar to global variables
– Makes testing harder
• Hidden Dependencies:
– Complicates dependency injection
• Threading & Serialization:
– Requires special handling
– Can be complex to implement correctly
3 Behavioural Patterns
3.1.1 Overview
3.1.2 Motivation
• Inspired by macros - recording actions for later execution
• Common in:
– GUIs
– Remote controls
– Job queues
– Multi-level undo systems
18
– AC units
• Uses Command objects instead of hardcoded logic
• Commands encapsulate device actions
• Remote only calls execute() without device knowledge
Role Description
Command Interface for executing operations
ConcreteCommand Implements execute() for receiver operations
Receiver Knows how to perform operations
Invoker Stores and triggers command execution
Client Creates commands and assigns to invoker
3.1.5 Benefits
• Encapsulates requests as objects
• Decouples sender from receiver
• Supports undo/redo functionality
• Enables command logging and queuing
3.1.6 Extensions
• Undo Commands:
– Requires undo() method
– Stores state for reversal
• Macro Commands:
– Multiple commands in sequence
– Single invocation executes all
• Lambda Commands:
– Java 8+ lambda expressions
– Replace concrete command classes
3.2.1 Overview
• Adapter Pattern: Converts incompatible interfaces
• Facade Pattern: Simplifies complex system interfaces
19
3.2.3 Adapter Pattern Participants
Role Description
Target Expected interface
Adapter Converts Adaptee to Target
Adaptee Existing incompatible class
Client Uses Target interface
Role Description
Facade Provides simple API to subsystem
Subsystem Handles actual complex logic
Client Uses Facade instead of direct interaction
Without Facade:
amplifier.on();
dvdPlayer.play();
projector.setMode(Widescreen);
// Complex for users
With Facade:
homeTheater.watchMovie();
// Hides unnecessary details
20
3.2.8 Adapter vs Facade Comparison
3.2.9 Summary
• Adapter:
– Makes incompatible interfaces work together
– Maintains existing code
– Enables reuse of legacy components
• Facade:
– Simplifies complex subsystems
– Reduces dependencies
– Improves maintainability
21