LINUX.ORG.RU

Вопрос гуру архитектурного дизайна приложений

 , , ,


0

5

Короче научившись всякими законами Деметры и начитавшись банды четырех, я столкнулся со следующей проблемой.

Есть класс Pivot. Этот класс умеет перемещяться в пространстве, так же перемещаться может еще и класс Model. Следовательно они наследуют следующий интерфейс:

class Movable{
    virtual setPosition(const vec3 &value) = 0;
    // еще куча сеттеров и геттеров
    virtual ~Movable() {}
}

Что бы не дублировать код и не плодить кучи атрибутов у класса я сделал класс Transform

class Transform{
    void setPosition(const vec3 &value);
    // куча геттеров и сеттеров
}

Сразу уже видно, что херня какая-то. Ладно идем дальше. Наследуем Pivot от Movable суем в него Transform и реализум методы setPosition у Pivot, в реализации будет трансляция чтото типа m_transform.setPosition(value); Такая же херня и у Model. Я не могу сделать AbstractMovable в котором я бы сделал все эту херню 1 раз, и Pivot с Model уже наследовал бы от него, но все правила не поощряют наследовать таким образом. Я хочу максимально следовать этим правилам. Вот как быть? Плодятся кучу методов, которые транслируются тупо в другой класс. Например Model наследует интерфейс Drawable, следовательно содержит параметр класс DrawRule, зависимости ростут, классы начинают уметь больно много вещей, вобщем нарушаются все эти законы. Как не нарушать?

Есть у кого что сказать по этому поводу? Я запутался нахрен!

Плодятся кучу методов, которые транслируются тупо в другой класс

Ну и что?

Например Model наследует интерфейс Drawable, следовательно содержит параметр класс DrawRule, зависимости ростут, классы начинают уметь больно много вещей

ЯННП.

вобщем нарушаются все эти законы. Как не нарушать?

А ты выбирай, какие законы нарушать. Есть, например, закон «do the simplest thing that might possibly work».

P.S. и купи себе спеллчекер, епт.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

кстати забыл... класс не должен делать много вещей. Так вот если следовать этому закону, то может получиться так:

void doSomething(){
    SomeClassA a;
    SomeClassB b;
    SomeResultA ra = a.doSomething(m_somethingPrivate);
    SomeResultB rb = b.doSomething(m_somethingPrivate, ra);
    // и т.д.
}
и получается куча зависимостей

pozitiffcat ★★★
() автор топика
Последнее исправление: pozitiffcat (всего исправлений: 1)

Что-то ты на пустом месте кучу писанины развёл по-моему. Movable, Drawable, SetUserable, UpdateUserPositionable на каждый чих будешь делать интерфейс?

Просто напиши сеттер и всё. void setPosition(const vec3 &position) { this.position = position; } без всяких интерфейсов, наследований, моделей и проксей.

Или подробней опиши, зачем ты это делаешь.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

Movable нужно, потому что он имеет parent-а, и мы не должны знать конкретную реализацию, ну ты понимаешь... т.е. setParentMovable(Movable* movable)

pozitiffcat ★★★
() автор топика
Ответ на: комментарий от pozitiffcat

Такое впечатление, что ты под веществами.

почему?

Горячечная невразумительная речь.

Реально же невозможно не нарушать правила

Ты нарисовал какой-то псевдокод (который лично мне ничего не говорит) и в ужасе мечешься, вереща «ОН НАРУШАЕТ ПРАВИЛА!!!11». Какие хоть правила он нарушает? Я не вижу в нем нарушения закона Деметры.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Да, закона Деметры он не нарушает, но зависимость очень большая. Когда я начинаю использовать в одном методе кучу классов, которые реализуют какую-то логику. Вот посмотрите только на это:

Mat4 Pivot::modelGlobalMatrix() const // этот же класс с такой же реализацией и в Model
{
    MovableMatrixConstructor mmc;
    return mmc.constructGlobalMatrix(this);
}
MovableMatrixConstructor высчитывает глобальную матрицу. Почему это в отдельном классе? Что бы небыло дублирования кода в Model, при расчетах.

Да на такой класс охренеешь юнит тест присать. Да и по сути класс-то ничего не умеет. Этот класс просто композиция разных классов, которые транслируют в них свои методы.

pozitiffcat ★★★
() автор топика
Последнее исправление: pozitiffcat (всего исправлений: 1)
Ответ на: комментарий от pozitiffcat

зависимость очень большая

Да где, блин?

MovableMatrixConstructor высчитывает глобальную матрицу. Почему это в отдельном классе?

Почему это в отдельном _классе_? Это подозрительно похоже на процедуру.

то бы небыло дублирования кода в Model

Какого кода? Сформулируй уже задачу (не классы, придуманные тобой, а задачу).

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

В какой метод я это вынесу? Что бы оба класса Model и Pivot могли заюзать его? ООП-же. Короче жопа какая-то с этими правилами.

pozitiffcat ★★★
() автор топика
Ответ на: комментарий от pozitiffcat

Если много какого то пересекающегося функционала у похожих объектов, то взаимодействие с ними можно вынести в отдельный класс, если очень хочется, конечно.

LiBer ★★★
()
Ответ на: комментарий от pozitiffcat

В какой метод я это вынесу?

В процедуру. Или у тебя ООП головного мозга?

Короче жопа какая-то с этими правилами.

Это не с правилами...

tailgunner ★★★★★
()

Что бы не дублировать код и не плодить кучи атрибутов у класса я сделал класс Transform

Вот тут я потерял ход мысли. Что за код будет дублироваться? Реализация setPosition() в каждом конкретном классе, который реализует Movable? Ну сделай миксин типа

class Moveable
{
public:
    Moveable(const vec3 &position) : m_position(position) {}
    virtual ~Moveable() {}

    virtual void setPosition(const vec3 &value)
    {
        m_position = value;
    }

protected:
    vec3 m_position;
};
И потом уже
class Point : public Moveable
{
public:
    Point() : Moveable(vec3(0, 0, 0)) {}

    // ...
};

ilammy ★★★
()
Последнее исправление: ilammy (всего исправлений: 3)
Ответ на: комментарий от ilammy

Ну наследование это хреново. Используйте композицию - говорят все умные книжки. Наследовать только интерфейсы а не реализацию.

pozitiffcat ★★★
() автор топика
Ответ на: комментарий от pozitiffcat

Ну, чувак. Ты или крестик сними, или трусы надень. А то у тебя: «Я хочу отнаследовать реализацию, чтобы не писать одинаковую реализацию везде, но только так, чтобы не отнаследовать реализацию».

Или так (ну можно ещё шаблонами причесть), или композиция: Movable-с-дефолтной-реализацией в виде поля Point и метод-заглушка, который реализует Moveable для Point, пробрасывая Point::setPosition() до того поля.

Упоротое ООП и стремление всё прятать за интерфейсами краткости кода не способствует.

ilammy ★★★
()

Есть еще правила SOLID. Так вот первое гласит: На каждый объект должна быть возложена одна единственная обязанность.

Допустим у меня есть Core, в котором есть DocumentBuilder, и DeviceManager. Впринципе Core сам не создает документы и не управляет устройствами, этим занимаются менеджеры. Core просто делегирует запросы. Можно ли так делать? Что имеется в виду этим правилом?

pozitiffcat ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.