Skip to content

Introduction to Design Patterns

Overview

Design patterns are reusable solutions to common software design problems, enabling modular, maintainable, and scalable code. In this first lesson of Section 3 in the Official CTO journey, we explore the fundamentals of design patterns, covering their purpose, categories (creational, structural, behavioral), and benefits. Whether building a notification system for a social app or a payment processor for an e-commerce platform, design patterns streamline your design process. By mastering them, you’ll write robust Java code and mentor others effectively.

Inspired by Design Patterns by Gang of Four, Head First Design Patterns, and Clean Code, this 15-minute lesson introduces the concepts, a practical Java example with a UML diagram, and practice exercises to kickstart your journey in Section 3. Let’s become a better engineer!

Learning Objectives

  • Understand the purpose and benefits of design patterns.
  • Learn the three categories: creational, structural, and behavioral patterns.
  • Apply OOP principles (Section 2, Lecture 1) to design patterns in Java.
  • Explore a simple pattern implementation for system design.

Why Design Patterns Matter

Design patterns provide proven solutions to recurring problems, saving time and ensuring quality. Early in my career, I used patterns to simplify a notification system for a social app, making it extensible for new notification types. Patterns—creational for object creation, structural for composition, and behavioral for interaction—enhance code reusability and maintainability. Explaining them clearly showcases your mentorship skills and prepares you for scalable system design.

In software engineering, design patterns help you:

  • Enhance Reusability: Apply proven solutions across projects.
  • Improve Maintainability: Write modular, clean code (Section 9).
  • Increase Scalability: Design systems that adapt to new requirements.
  • Teach Effectively: Share design strategies with teams.

Key Concepts

1. What Are Design Patterns?

Design patterns are reusable templates for solving common software design problems, formalized by the Gang of Four (Design Patterns). They provide a common vocabulary and structure for developers.

Purpose:

  • Solve recurring problems (e.g., object creation, system communication).
  • Promote best practices for modularity and extensibility.
  • Align teams with standardized solutions.

2. Categories of Design Patterns

  • Creational: Manage object creation (e.g., Singleton, Factory Method).
  • Structural: Organize classes/objects (e.g., Adapter, Decorator).
  • Behavioral: Define interactions (e.g., Strategy, Observer).

3. Benefits of Design Patterns

  • Modularity: Encapsulate logic for low coupling (Section 2, Lecture 1).
  • Extensibility: Support new features without major changes.
  • Clarity: Use UML to visualize designs (Section 2, Lecture 2).

Use Case: Design a notification system with extensible notification types.

Code Example: Notification System

Let’s design a simple notification system for a social app, using Java to demonstrate OOP and a basic pattern setup, with a UML class diagram.

UML Class Diagram

+---------------------+       1       +---------------------+
| NotificationService |-------------|   Notification      |
+---------------------+       1..*   +---------------------+
| -notifications: List<Notification> | -message: String |
+---------------------+              +---------------------+
| +sendNotification(message, type) | | +send()            |
+---------------------+              +---------------------+
                                            |
                                            | implements
                            +-------------+-------------+
                            |                           |
                   +----------------+           +----------------+
                   | EmailNotification |       | PushNotification |
                   +----------------+           +----------------+
                   | +send          |           | +send          |
                   +----------------+           +----------------+

Java Implementation

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

// Notification interface
public interface Notification {
    void send();
}

// EmailNotification class
public class EmailNotification implements Notification {
    private String message;
    
    public EmailNotification(String message) {
        this.message = message;
    }
    
    @Override
    public void send() {
        System.out.println("Sending email notification: " + message);
    }
}

// PushNotification class
public class PushNotification implements Notification {
    private String message;
    
    public PushNotification(String message) {
        this.message = message;
    }
    
    @Override
    public void send() {
        System.out.println("Sending push notification: " + message);
    }
}

// NotificationService class
public class NotificationService {
    private List<Notification> notifications;
    
    public NotificationService() {
        this.notifications = new ArrayList<>();
    }
    
    public void sendNotification(String message, String type) {
        Notification notification;
        if (type.equals("email")) {
            notification = new EmailNotification(message);
        } else if (type.equals("push")) {
            notification = new PushNotification(message);
        } else {
            throw new IllegalArgumentException("Unknown notification type: " + type);
        }
        notifications.add(notification);
        notification.send();
    }
    
    // Example usage
    public static void main(String[] args) {
        NotificationService service = new NotificationService();
        service.sendNotification("Welcome to the app!", "email");
        service.sendNotification("New message received!", "push");
        // Output: Sending email notification: Welcome to the app!
        //         Sending push notification: New message received!
    }
}
  • OOP and Design Principles:
    • Encapsulation: Private message field with constructor.
    • Polymorphism: Notification interface supports multiple types.
    • Abstraction: NotificationService hides implementation details.
    • Clean Code: Meaningful names, modularity (Section 9).
  • Big O: O(1) for sendNotification, O(n) for iterating notifications if needed.
  • Edge Cases: Handles invalid notification types, empty messages.
  • Pattern Setup: Introduces a basic pattern-like structure (foreshadows Factory Method in Lecture 3).

Systematic Approach:

  • Clarified requirements (send notifications, support multiple types).
  • Designed UML diagram to model NotificationService and Notification.
  • Implemented Java classes with OOP principles.
  • Tested with main method for functionality.

Real-World Application

Imagine designing a notification system for a social app, where users receive emails or push notifications. Using a polymorphic Notification interface ensures extensibility for new types (e.g., SMS), while encapsulation keeps the system modular. This approach—leveraging OOP and pattern-like structures—enhances scalability and demonstrates your ability to mentor teams on robust design.

Practice Exercises

Apply design pattern concepts with these exercises:

  • Easy: Design a UML diagram and Java code for a Logger system with ConsoleLogger and FileLogger classes.
  • Medium: Create a UML diagram and Java code for a MessageQueue system with EmailQueue and SMSQueue classes.
  • Medium: Implement a PaymentProcessor with CreditCard and PayPal types using an interface.
  • Hard: Design a ContentDelivery system with Video and Article types, ensuring extensibility.

Try designing one system in Java with a UML diagram, focusing on OOP principles and modularity.

Conclusion

Design patterns provide reusable solutions for scalable Java systems. By understanding their purpose and categories, you’ll build robust software, optimize designs, and teach others effectively. This starts Section 3 of the Official CTO journey, setting you up for deeper pattern exploration.

Next Step: Explore Singleton Pattern to learn single-instance design, or check out all sections to continue your journey.