An Interface Segregation Principle (ISP) example

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

struct IObject {
    virtual ~IObject() = default;

    /// Returns the name of the object.
    virtual std::string getName() const = 0;

    /// Prints a textual description of the object.
    virtual void describe() const = 0;

    /// Eats another object.
    virtual bool eat(IObject* other) = 0;
};
/// `bark()` has volume in decibels.
/// `walk()` now takes coordinates (x, y).
struct IDog : IObject {
    /// Bark with given loudness (in dB).
    virtual void bark(double volumeDb) const = 0;

    /// Walk to a given position (x, y) in meters.
    virtual void walk(double x, double y) const = 0;
};

/// `swim()` receives a depth parameter (in meters).
struct IFish : IObject {
    /// Swim at a given depth (in meters).
    virtual void swim(double depthMeters) const = 0;
};

struct Bulldog : IDog {
    std::string getName() const override { return "Bulldog"; }

    void describe() const override {
        std::cout << getName() << " — a strong and loyal dog.\n";
    }

    void bark(double volumeDb) const override {
        if (volumeDb < 30.0)
            std::cout << "Bulldog barks softly (" << volumeDb << " dB).\n";
        else if (volumeDb < 70.0)
            std::cout << "Bulldog barks normally (" << volumeDb << " dB).\n";
        else
            std::cout << "Bulldog barks very loudly (" << volumeDb << " dB)!\n";
    }

    void walk(double x, double y) const override {
        std::cout << "Bulldog walks to position (" << x << ", " << y << ").\n";
    }
};

struct Chihuahua : IDog {
    std::string getName() const override { return "Chihuahua"; }

    void describe() const override {
        std::cout << getName() << " — a tiny but energetic dog.\n";
    }

    void bark(double volumeDb) const override {
        if (volumeDb < 20.0)
            std::cout << "Chihuahua yaps quietly (" << volumeDb << " dB).\n";
        else if (volumeDb < 50.0)
            std::cout << "Chihuahua yaps sharply (" << volumeDb << " dB).\n";
        else
            std::cout << "Chihuahua squeals at max power (" << volumeDb << " dB)!\n";
    }

    void walk(double x, double y) const override {
        std::cout << "Chihuahua runs quickly to (" << x << ", " << y << ").\n";
    }
};

struct Goldfish : IFish {
    std::string getName() const override { return "Goldfish"; }

    void describe() const override {
        std::cout << getName() << " — a small shiny fish.\n";
    }

    void swim(double depthMeters) const override {
        if (depthMeters < 1.0)
            std::cout << "Goldfish swims near the surface (" << depthMeters << " m).\n";
        else if (depthMeters < 5.0)
            std::cout << "Goldfish swims deeper (" << depthMeters << " m).\n";
        else
            std::cout << "Goldfish rarely swims that deep (" << depthMeters << " m)!\n";
    }
};

struct Shark : IFish {
    std::string getName() const override { return "Shark"; }

    void describe() const override {
        std::cout << getName() << " — a large predator fish.\n";
    }

    void swim(double depthMeters) const override {
        std::cout << "Shark swims powerfully at " << depthMeters << " meters depth.\n";
    }
};

std::vector<std::shared_ptr<IObject>> internalMakeObjects()
{
    std::vector<std::shared_ptr<IObject>> objects; 

    objects.push_back(std::make_shared<Bulldog>());
    objects.push_back(std::make_shared<Chihuahua>());
    objects.push_back(std::make_shared<Goldfish>());
    objects.push_back(std::make_shared<Shark>());

    return objects;
}

std::shared_ptr<IObject> externalAlgorithm(std::vector<std::shared_ptr<IObject>>& objects);

void processAnimal(const std::shared_ptr<IObject>& obj)
{
    if (auto dog = std::dynamic_pointer_cast<IDog>(obj)) {
        dog->bark(25.0);
        dog->walk(1.0, 2.0);
    } else if (auto fish = std::dynamic_pointer_cast<IFish>(obj)) {
        fish->swim(0.5);
    }
}

int main()
{
    // Creates not only Dogs and Fishes, but objects of different types like cheburashkas.
    std::vector<std::shared_ptr<IObject>> objects = externalMakeObjects();
 
    std::cout << "--- Descriptions ---\n";
    for (const auto& obj : objects)
        obj->describe();
 
    std::cout << "\n--- Actions ---\n";
    // But we can work only with Dogs and Fishes.
    for (const auto& obj : objects) {
        processAnimal(obj);
    }
 
    {
        std::shared_ptr<IObject> found = externalAlgorithm(objects);
    
        processAnimal(found);
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *