Design Patterns in OOP

Understanding Common Design Patterns in C++

What are Design Patterns?

Design Patterns are reusable solutions to common software design problems. They provide templates for solving recurring design problems and help create more maintainable, flexible, and reusable code. Design patterns are categorized into three main types: Creational, Structural, and Behavioral patterns.

Design Patterns क्या हैं? (हिंदी में)

Design Patterns common software design problems के लिए reusable solutions हैं। यह recurring design problems को solve करने के लिए templates provide करते हैं और more maintainable, flexible, और reusable code create करने में help करते हैं। Design patterns को तीन main types में categorize किया गया है: Creational, Structural, और Behavioral patterns।

Key Points:

  • Reusability: Solutions to common problems
  • Maintainability: Well-tested approaches
  • Flexibility: Adaptable to different situations
  • Communication: Common vocabulary for developers

Types of Design Patterns

Creational Patterns

Singleton, Factory, Builder, etc.

Structural Patterns

Adapter, Bridge, Composite, etc.

Behavioral Patterns

Observer, Strategy, Command, etc.

Pattern Rules

Rule Description
Problem-Solution Address specific design problems
Reusability Can be applied in different contexts
Flexibility Adaptable to different situations
Maintainability Well-documented and tested

Simple Example

#include <iostream>
#include <memory>
#include <string>
#include <vector>

// Singleton Pattern
class Singleton {
private:
    static Singleton* instance;
    Singleton() {}
    
public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
    
    void doSomething() {
        std::cout << "Singleton doing something" << std::endl;
    }
};

Singleton* Singleton::instance = nullptr;

// Factory Pattern
class Product {
public:
    virtual void operation() = 0;
    virtual ~Product() = default;
};

class ConcreteProductA : public Product {
public:
    void operation() override {
        std::cout << "ConcreteProductA operation" << std::endl;
    }
};

class ConcreteProductB : public Product {
public:
    void operation() override {
        std::cout << "ConcreteProductB operation" << std::endl;
    }
};

class Factory {
public:
    static std::unique_ptr<Product> createProduct(const std::string& type) {
        if (type == "A") {
            return std::make_unique<ConcreteProductA>();
        } else if (type == "B") {
            return std::make_unique<ConcreteProductB>();
        }
        return nullptr;
    }
};

// Observer Pattern
class Observer {
public:
    virtual void update(const std::string& message) = 0;
    virtual ~Observer() = default;
};

class Subject {
private:
    std::vector<Observer*> observers;
    
public:
    void attach(Observer* observer) {
        observers.push_back(observer);
    }
    
    void detach(Observer* observer) {
        observers.erase(
            std::remove(observers.begin(), observers.end(), observer),
            observers.end()
        );
    }
    
    void notify(const std::string& message) {
        for (auto observer : observers) {
            observer->update(message);
        }
    }
};

class ConcreteObserver : public Observer {
private:
    std::string name;
    
public:
    ConcreteObserver(const std::string& n) : name(n) {}
    
    void update(const std::string& message) override {
        std::cout << name << " received: " << message << std::endl;
    }
};

// Function demonstrating design patterns
void designPatternExample() {
    std::cout << "\nDesign Pattern Example:" << std::endl;
    
    // Singleton Pattern
    Singleton* singleton = Singleton::getInstance();
    singleton->doSomething();
    
    // Factory Pattern
    auto productA = Factory::createProduct("A");
    auto productB = Factory::createProduct("B");
    
    productA->operation();
    productB->operation();
    
    // Observer Pattern
    Subject subject;
    ConcreteObserver observer1("Observer1");
    ConcreteObserver observer2("Observer2");
    
    subject.attach(&observer1);
    subject.attach(&observer2);
    
    subject.notify("Hello Observers!");
    
    subject.detach(&observer1);
    subject.notify("Observer1 detached");
}

int main() {
    designPatternExample();
    return 0;
}

उदाहरण की व्याख्या (Example Explanation)

इस उदाहरण में design patterns के different aspects को demonstrate किया गया है:

  • Singleton Pattern: Single instance का management
  • Factory Pattern: Object creation का abstraction
  • Observer Pattern: Event handling और notification
  • Pattern Implementation: Different patterns का practical use
  • Smart Pointers: Modern C++ features का use
  • Pattern Interaction: Different patterns का combination

Benefits of Design Patterns

Design Patterns के फायदे

  1. Code Quality
    • Well-tested solutions
    • Maintainable code
  2. Communication
    • Common vocabulary
    • Better understanding
  3. Flexibility
    • Adaptable solutions
    • Reusable code

Best Practices

  • Choose appropriate pattern for the problem
  • Don't overuse patterns
  • Understand pattern trade-offs
  • Consider pattern combinations
  • Document pattern usage