Agent Skills: OOP Patterns Skill

>

object-oriented-programmingdesign-patternssoftware-designarchitecture-patterns
designID: pluginagentmarketplace/custom-plugin-cpp/oop-patterns

Skill Files

Browse the full folder contents for oop-patterns.

Download Skill

Loading file tree…

skills/oop-patterns/SKILL.md

Skill Metadata

Name
oop-patterns
Description
>

OOP Patterns Skill

Production-Grade Learning Skill | Object-Oriented Design

Master C++ OOP concepts and industry-standard design patterns.


The Four Pillars

1. Encapsulation

class BankAccount {
private:
    std::string id_;
    double balance_{0.0};  // Default member init

public:
    explicit BankAccount(std::string id) : id_(std::move(id)) {}

    // Read-only access
    [[nodiscard]] double balance() const { return balance_; }
    [[nodiscard]] const std::string& id() const { return id_; }

    // Controlled mutation with validation
    void deposit(double amount) {
        if (amount <= 0) {
            throw std::invalid_argument("Amount must be positive");
        }
        balance_ += amount;
    }

    bool withdraw(double amount) {
        if (amount <= 0 || amount > balance_) return false;
        balance_ -= amount;
        return true;
    }
};

2. Inheritance

// Abstract base class
class Shape {
protected:
    std::string name_;

public:
    explicit Shape(std::string name) : name_(std::move(name)) {}
    virtual ~Shape() = default;  // ALWAYS virtual destructor!

    // Pure virtual functions (interface)
    [[nodiscard]] virtual double area() const = 0;
    [[nodiscard]] virtual double perimeter() const = 0;

    // Non-virtual (shared behavior)
    [[nodiscard]] const std::string& name() const { return name_; }
};

class Circle final : public Shape {  // final prevents further inheritance
    double radius_;
public:
    explicit Circle(double r) : Shape("Circle"), radius_(r) {}

    [[nodiscard]] double area() const override {
        return std::numbers::pi * radius_ * radius_;
    }

    [[nodiscard]] double perimeter() const override {
        return 2 * std::numbers::pi * radius_;
    }
};

3. Polymorphism

// Runtime polymorphism via virtual functions
void printShape(const Shape& shape) {
    std::cout << shape.name() << ": area = " << shape.area() << "\n";
}

// Usage - same function, different behavior
std::vector<std::unique_ptr<Shape>> shapes;
shapes.push_back(std::make_unique<Circle>(5.0));
shapes.push_back(std::make_unique<Rectangle>(3.0, 4.0));

for (const auto& shape : shapes) {
    printShape(*shape);  // Polymorphic dispatch
}

4. Abstraction

// Pure interface (all pure virtual)
class ILogger {
public:
    virtual ~ILogger() = default;
    virtual void log(std::string_view message) = 0;
    virtual void setLevel(int level) = 0;
};

// Multiple implementations
class ConsoleLogger : public ILogger {
public:
    void log(std::string_view message) override {
        std::cout << "[LOG] " << message << "\n";
    }
    void setLevel(int) override { }
};

class FileLogger : public ILogger {
    std::ofstream file_;
public:
    explicit FileLogger(const std::string& path) : file_(path) {}
    void log(std::string_view message) override {
        file_ << message << "\n";
    }
    void setLevel(int) override { }
};

SOLID Principles

| Principle | Summary | C++ Example | |-----------|---------|-------------| | Single Responsibility | One class, one reason to change | Separate User from UserSerializer | | Open/Closed | Open for extension, closed for modification | Virtual functions, inheritance | | Liskov Substitution | Subtypes must be substitutable | Square shouldn't inherit Rectangle | | Interface Segregation | Prefer small, specific interfaces | Split IWorker into IWorkable, IFeedable | | Dependency Inversion | Depend on abstractions | Inject IDatabase& not MySQLDatabase |


Design Patterns

Factory Pattern

class ShapeFactory {
public:
    static std::unique_ptr<Shape> create(std::string_view type, double param) {
        if (type == "circle") {
            return std::make_unique<Circle>(param);
        }
        if (type == "square") {
            return std::make_unique<Square>(param);
        }
        throw std::invalid_argument("Unknown shape type");
    }
};

// Usage
auto shape = ShapeFactory::create("circle", 5.0);

Singleton Pattern (Thread-Safe)

class Logger {
private:
    Logger() = default;

public:
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;

    static Logger& instance() {
        static Logger instance;  // Thread-safe in C++11
        return instance;
    }

    void log(std::string_view msg) { std::cout << msg << "\n"; }
};

Observer Pattern

class IObserver {
public:
    virtual ~IObserver() = default;
    virtual void onNotify(const std::string& event) = 0;
};

class Subject {
    std::vector<IObserver*> observers_;
public:
    void attach(IObserver* obs) { observers_.push_back(obs); }
    void detach(IObserver* obs) {
        observers_.erase(std::remove(observers_.begin(), observers_.end(), obs),
                        observers_.end());
    }
    void notify(const std::string& event) {
        for (auto* obs : observers_) {
            obs->onNotify(event);
        }
    }
};

Strategy Pattern

class ICompressionStrategy {
public:
    virtual ~ICompressionStrategy() = default;
    virtual std::vector<uint8_t> compress(std::span<const uint8_t> data) = 0;
};

class ZipStrategy : public ICompressionStrategy {
public:
    std::vector<uint8_t> compress(std::span<const uint8_t> data) override {
        // ZIP compression
        return {};
    }
};

class Compressor {
    std::unique_ptr<ICompressionStrategy> strategy_;
public:
    void setStrategy(std::unique_ptr<ICompressionStrategy> s) {
        strategy_ = std::move(s);
    }
    std::vector<uint8_t> compress(std::span<const uint8_t> data) {
        return strategy_->compress(data);
    }
};

Troubleshooting

| Issue | Cause | Solution | |-------|-------|----------| | Object slicing | Passing by value | Use references/pointers | | Memory leak | Missing virtual destructor | Add virtual ~Base() = default; | | Diamond problem | Multiple inheritance | Use virtual inheritance | | Tight coupling | Direct dependencies | Inject interfaces |


Unit Test Template

#include <gtest/gtest.h>

TEST(ShapeTest, CircleArea) {
    Circle c(5.0);
    EXPECT_NEAR(c.area(), 78.5398, 0.0001);
}

TEST(ShapeTest, Polymorphism) {
    std::unique_ptr<Shape> shape = std::make_unique<Circle>(1.0);
    EXPECT_EQ(shape->name(), "Circle");
}

TEST(FactoryTest, CreateCircle) {
    auto shape = ShapeFactory::create("circle", 5.0);
    EXPECT_NE(shape, nullptr);
    EXPECT_EQ(shape->name(), "Circle");
}

C++ Plugin v3.0.0 - Production-Grade Learning Skill