CSCI 370 Lecture 12 Review Sheet: Design Principles, Software Process Models, and the Singleton & Factory Patterns
โ Key Topics Covered
- Functional vs. Non-Functional Requirements
- Software Process Models (Agile, Waterfall, Incremental)
- Design Principles (Composition over Inheritance, Open/Closed Principle)
- Design Patterns Overview (Singleton, Factory, Strategy, Observer)
- UML Relationships (Inheritance, Composition, Association)
- Software Maintainability & Reusability
- Singleton & Factory Pattern Java Implementations
- Design Pattern Benefits and Interview Tips
๐ Functional vs. Non-Functional Requirements
Functional Requirements describe what the system should do, i.e., the features and functionalities requested by the user or client.
Non-Functional Requirements describe how the system performs a function, covering broader system attributes like performance, usability, reliability, etc. They often span multiple functional requirements.
Example: A system must process user logins (functional) and must do so within 2 seconds (non-functional).
๐ฉ๏ธ Cloud Software Benefits
- No need for internal maintenance
- Scalability and flexibility
- Accessible from anywhere
- Automatic updates
Correct answer to the multiple-choice example: All of the above
๐ง Design Principles
Composition Over Inheritance
- Composition: Using object references to other classes to build functionality. Preferred in many cases because it avoids the tight coupling of inheritance.
- Inheritance: โIs-aโ relationship, tightly couples subclasses with their superclasses. Can lead to fragile systems.
Example: A
MedicalRecord
class contains aDatabase
object => Composition (โhas-aโ)
Open/Closed Principle
- Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.
- Supported by patterns like Strategy, Observer, and State.
๐งช Incremental Development and Agile Models
Incremental development includes:
- Agile, Scrum, Extreme Programming (XP)
- Encourages continuous integration and frequent feedback
- Customer involvement is essential
Models not using incremental development:
- Waterfall โ a linear, phased approach used when changes are costly or infeasible.
โ๏ธ When to Use the Waterfall Model
Used when changes are expensive or difficult after development begins. Examples:
- Medical software (regulated by FDA)
- Airplane systems (regulated by FAA)
Reasons:
- Requires certification
- Changes trigger extensive revalidation
Not suitable for:
- Games
- E-commerce platforms
๐งฌ UML and Object-Oriented Relationships
Types of Relationships:
- Inheritance: A class โis aโ type of another class (denoted by a solid line with a triangle arrowhead)
- Composition: A class โhas aโ reference to another class; ownership implies lifecycle control
- Association: General binary relationship; can be one-way or bidirectional
Examples:
MedicalRecord
composesDatabase
=> โhas-aโDatabase
is public => no encapsulation, therefore not protected
โ๏ธ Singleton Pattern (Java Implementation)
Problem Being Solved
- Global variables are dangerous because they can be modified from anywhere, making the logic of the program hard to follow and debug.
- Example: A variable like
id
being set to-100
arbitrarily in some part of the code.
Solution: Singleton Pattern
- Encapsulation: Make the global variable private.
- Access Control: Provide a public getter method (
getId()
) that returns the value without allowing direct modification.
Purpose
- Restricts instantiation of a class to a single object.
- Controls access to a shared resource (e.g., ID generator, database connection).
- Protects global variables from unauthorized modification.
Two Forms of Singleton
1. Eager Initialization
private static NextId instance = new NextId();
- Instance is created at load time.
- Suitable when the instance is always needed and simple to construct.
2. Lazy Initialization
private static DatabaseConnection connection = null;
public static DatabaseConnection getConnection() {
if (connection == null) {
connection = new DatabaseConnection();
}
return connection;
}
- Created only on first use.
- More flexible but requires attention to thread-safety.
Common Issue: Thread Safety
- Multiple threads may call the getter simultaneously and create multiple instances.
- Fix: Use
synchronized
methods or other concurrency techniques.
๐ญ Factory Pattern (Java Implementation)
Purpose
- Encapsulates object creation based on logic (e.g., age, type).
- Provides a single access point for instantiation.
- Promotes code reuse and consistency.
Benefits
- Hides object creation logic.
- Reduces dependency on concrete classes.
- Easier to manage and update creation logic in one place.
Example from Class
public Bicycle getNewBicycle(int age) {
if(age < 6)
return new KidsTriCycle();
if(age < 19)
return new TenSpeedBicycle();
return new MotorCycle();
}
Java Usage
Bicycle bicycle = new BicycleFactory().getNewBicycle(6);
bicycle.ride();
- Factory prevents misuse of
new
operator. - Ensures correct object type is instantiated depending on criteria.
๐๏ธ Observer Pattern
Purpose
- Implements a publish-subscribe model: one subject notifies multiple observers.
- Observers implement a shared interface (e.g.,
notify()
).
Benefit
- Loose coupling between subject and observers.
- Flexible and modular; easy to add/remove observers.
Example
interface Observer {
void notify();
}
StockMarket
notifiesWallStreet
andSEC
which both implementObserver
.
๐งฉ Strategy Pattern
Purpose
- Replaces inheritance with composition to inject behavior at runtime.
Principle
- Favor composition over inheritance.
- Supports Open/Closed Principle: open for extension, closed for modification.
Example
Duck d = new Duck(new RealFly(), new LoudQuack());
RealFly
andLoudQuack
implementFlyBehavior
andQuackBehavior
- Can swap strategies without changing Duck class
๐งญ Software Project Lifecycle Phases (Correct Order)
- Feasibility Study โ Can it be built within budget/tech constraints?
- Requirements โ Define what the system should do
- Design โ Architecting system components
- Development โ Actual coding
- Testing โ Verify correctness and reliability
- (Optional) Deployment, Maintenance
๐ Reusability and Maintainability
- Reusability: Design components/modules that can be reused across projects
- Maintainability: Especially important in high employee turnover environments
- Ensures knowledge isnโt lost
- Simplifies onboarding
๐จโ๐ป Software Engineering Essentials
- You donโt need a degree to be a software engineer
- A software project involves more than code:
- People
- Hardware
- Budget
- Legal/regulatory constraints
๐ Summary of Design Patterns Covered
Pattern | Purpose | Benefit |
---|---|---|
Singleton | One instance only; global control | Prevents uncontrolled access to shared resource |
Factory | Encapsulate object creation | Easy, centralized, controlled instantiation |
Observer | Notify multiple dependent objects on state change | Loose coupling, unified notification interface |
Strategy | Behavior injection using composition | Flexible, avoids inheritance problems |
๐ฌ Interview Tips
- Singleton: Be ready to discuss thread-safety and when to use lazy vs. eager loading.
- Factory: Emphasize how it helps encapsulate and control object creation.
- Observer: Focus on decoupling and flexibility.
- Strategy: Highlight extensibility and code maintainability through composition.
๐ Summary
This lecture focused on core design principles and the practical implications of software development models. Key design patterns like Singleton, Factory, Observer, and Strategy help implement robust, modular, and maintainable systems. Singleton prevents issues with shared state, Factory simplifies object creation, Observer supports publish-subscribe architecture, and Strategy encourages behavior flexibility. Understanding when and how to apply these patterns is essential for real-world software engineering.