Как сделать код универсальным и масштабируемым

Рейтинг: 0Ответов: 1Опубликовано: 21.08.2023

Я работаю над программой, которая создает участки земли и их владельцев. В моей реализации есть базовый класс Shape, а также два класса-наследника Rectangle и Square. У каждого участка есть площадь и владелец.Я хотел бы получить советы по улучшению архитектуры этой программы с целью сделать ее более масштабируемой и гибкой для добавления новых типов участков в будущем, а также для обеспечения эффективной работы с владельцами.

В частности, меня интересует оптимизация кода для поддержки новых типов участков без изменения основных структур, а также советы по организации кода, чтобы он был более читаемым и понятным. Также хотел бы услышать мнения о текущей структуре классов Owner, Shape, Rectangle и Square.Буду признателен за любые предложения и советы по улучшению этой реализации. Спасибо заранее!

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>

class Owner
{
private:
    std::string name;

public:
   Owner(std::string&& name) noexcept : name(std::move(name)) {}
   Owner(const std::string& name) : name(name) {}

    friend std::ostream& operator<<(std::ostream& out, const Owner& owner)
    {
        return out << "Owner(" << owner.name << ")";
    }

    Owner& operator=(const Owner& other) noexcept
    {
        if (this != &other)
            name = other.name;

        return *this;
    }
};

class Shape
{
public:
    virtual double getArea() const = 0;
    virtual const  Owner& getOwner() const = 0;
    virtual void printInfo() const = 0;
    virtual ~Shape() = default;
};

class Rectangle : public Shape
{
private:
    double m_width;
    double m_height;
    Owner m_owner; //Участки не могут существовать без владельца 

public:
    Rectangle(double width, double height, const Owner& owner)
        : m_width(width), m_height(height), m_owner(owner) {}

    double getArea() const override { return m_width * m_height;}

    const Owner& getOwner() const override { return m_owner; }


    void printInfo() const override
    {
        std::cout << "Rectangle:\n"
            << "  Width: " << m_width << '\n'
            << "  Height: " << m_height << '\n'
            << "  Owner: " << m_owner << '\n'
            << "  Area: " << getArea();
    }
};

class Square : public Shape 
{
private:
    double m_side;
    Owner m_owner;//Участки не могут существовать без владельца 

public:
    Square(double side, const Owner& owner) 
        : m_side(side), m_owner(owner) {} 

    double getArea() const override { return m_side * m_side; }

    const Owner& getOwner() const override { return m_owner; }

    void printInfo() const override
    {
        std::cout << "Square:\n";
        std::cout << "  Side: " << m_side << '\n';
        std::cout << "  Owner: " << m_owner << '\n';
        std::cout << "  Area: " << getArea();
    }
};

void AddObject()
{
    std::vector<std::unique_ptr<Shape>> Shapes;
    std::string SquareName = "alice";
    std::string RectangleName = "jhon"; 

    Owner owner1(std::move(SquareName));
    Owner owner2(std::move(RectangleName)); 
    

    Shapes.push_back(std::make_unique<Square>(5, std::move(owner1))); 
    Shapes.push_back(std::make_unique<Rectangle>(4, 7, std::move(owner2))); 
     

    for (const auto& plot : Shapes)
    {
        plot->printInfo();
        std::cout << "\n\n";
    }
}

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

Ответы

▲ 0

Ничуть не настаивая на своем мнении :), навскидку предлагаю вариант.

Не уверен, что надо городить отдельный класс Owner, так что удаляем его вовсе. Если бы в нем была еще какая-то функциональность... Но можно и оставить, особенно если планируется расширение понятия "владелец" и его функциональности; но в любом случае, раз участков без владельцев нет — то владелец есть неотъемлемой частью Shape. Конечно, логичнее хранить указатель на владельца — ведь один владелец может владеть и несколькими участками. Тогда действительно нужен класс Owner, в котором есть в том или ином виде список участков...

Квадрат — это прямоугольник с двумя равными сторонами. Чем и воспользуемся.

class Shape
{
public:
    Shape(const std::string& owner):owner(owner){}
    virtual double getArea() const = 0;
    virtual const  std::string& getOwner() const { return owner; };
    virtual void printInfo() const = 0;
    virtual ~Shape() = default;
private:
    std::string owner; //Участки не могут существовать без владельца 
};

class Rectangle : public Shape
{
protected:
    double m_width;
    double m_height;
public:
    Rectangle(double width, double height, const std::string& owner)
        : Shape(owner), m_width(width), m_height(height) {}

    double getArea() const override { return m_width * m_height;}

    void printInfo() const override
    {
        std::cout << "Rectangle:\n"
            << "  Width: " << m_width << '\n'
            << "  Height: " << m_height << '\n'
            << "  Owner: " << getOwner() << '\n'
            << "  Area: " << getArea();
    }
};

class Square : public Rectangle
{
public:
    Square(double side, const std::string& owner):Rectangle(side,side,owner){}

    void printInfo() const override
    {
        std::cout << "Square:\n";
        std::cout << "  Side: " << m_width << '\n';
        std::cout << "  Owner: " << getOwner() << '\n';
        std::cout << "  Area: " << getArea();
    }
};

void AddObject()
{
    std::vector<std::unique_ptr<Shape>> Shapes;
    std::string SquareName    = "alice";
    std::string RectangleName = "jhon"; 

    Shapes.push_back(std::make_unique<Square>(5, SquareName));
    Shapes.push_back(std::make_unique<Rectangle>(4, 7, RectangleName));

    for (const auto& plot : Shapes)
    {
        plot->printInfo();
        std::cout << "\n\n";
    }
}

int main()
{
    AddObject();
}