Pull to refresh

Comments 4

Благодарю за статью! Есть интересные идеи и есть что обсудить

Мне кажется, в статье происходит смешение теплого с мягким :)

Что не есть плохо, но нужно тогда уже доводить до конца реализацию получающегося тепло-мягкого :)

SOLID - это ведь не догмы, и не аксиомы "как правильно", это набор идей призывающий к упрощению контекста разработки :)

И поэтому приведенный пример с нарушением принципа разделения интерфейсов - далеко не всегда является нарушением. Причем, как на уровне цели упрощения контекста, так и на уровне буквы.

Будем ли мы думать про аспект авторизации во время работы над интерфейсом и реализацией профиля? Очень вероятно, что да. И нам придется вводить часть нашего кода, посвященную авторизации, в контекст в котором мы работаем над профилем.

При этом, честное разделение двух этих интерфейсов - не создаёт для нас никаких дополнительных проблем, кроме того, что для обнаружения смысловой связи между его частями (если она есть) - нам придётся дойти до точки, где эти элементы используются вместе.

При этом, нужно понимать, что аналогичная проблема, в целом, есть и у миксинов, и с какой-то точки зрения, она даже страшнее, ведь миксины не создают явного наследования, но при этом все ещё создают зависимость.

В общем, не совсем понятно: а главное зачем? Потому что в данном примере нам или не нужны ни миксины, ни наследование, если контекст профиля и авторизации не может быть полностью изолирован. Или мы можем честно разделить интерфейсы не имея ВООБЩЕ НИКАКИХ ПРОБЛЕМ, потому что нам никогда не нужно будет думать о них в одном контексте :)

P.S. буду рад, если меня кто-то поправит, я много лет уже пытаюсь понять в чем преимущество миксинов :D

P.S. буду рад, если меня кто-то поправит, я много лет уже пытаюсь понять в чем преимущество миксинов :D

Я не берусь рассуждать о том, что написано в этой статье, но вот про преимущество миксинов сказать хочется)

На мой взгляд это действительно классная штука, и это что-то вроде попытки сделать множественное наследование безопасным. При должном опыте и/или усердии, можно грамотно нарезать функционал на миксины, и потом собирать из них как из кубиков различные классы, с разным поведением. Если добавить к ним еще интерфейсы, и учесть что миксинами можно затыкать реализации интерфейсов, то получается вообще классно. Как грубый пример, можно создать интерфейс монстра, монстр может атаковать, и монстр может двигаться. Но у вас есть по 10 различных идей, как именно монстр может двигаться, и по 10 как атаковать. Реализовав по 10 миксинов для обоих случаев, вы получаете 100 классов-монстров, с любой комбинацией этих двух действий, как только захочется. И чтобы создать очередной такой класс, достаточно всего то, написать что-то вроде

class SomeMonster with SomeAttackMixin, SomeMoveMixin implements IMonster {}

Да, конечно можно сказать, что тоже самое можно было бы сделать компонентным подходом, подпихивая через DI оба класса с реализованным поведением для каждого действия, и проксируя их в самом классе, при реализации интерфейса. Но с миксинами имхо это выглядит поизящнее и погибче, во первых потому что хорошо когда интерфейс состоит из двух методов, и ты затыкаешь его двумя миксинами, и соответственно двумя прокси методами через DI, совсем другое, когда таких методов 10, и рождается куча бойлерплейт кода, по типу

void attack() {
  _attackService.attack();
}

Во вторых, представьте что у вас есть монстры, которые в середине атаки вынуждены, например, подзарядиться энергией, тогда некоторые методы атаки будут выглядеть как:
1. начало атаки
2. подзарядка
3. конец атаки

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

mixin SomeAttackMixin implements IMonster {
  void attack() {
    print("Start attack");
    feed();
    print("End attack");
  }

  void feed();
}

соответственно, метод feed может реализовать либо миксин, который подмешивается вслед за миксином SomeAttackMixin, либо уже конечный класс. В первом случае, можно насоздавать еще 10 миксинов, реализующих feed метод (используя конструкцию on для миксинов, или implement, смотря что вам больше подходит). И эти 10 миксинов с feed методом, могут начать участвовать в комбинациях with, по созданию конечного класса.
А вот в случае компонентного подхода, уже начинаются сложности, по типу инжектировать в конечный класс другой класс, в который инжектировать еще один...Выглядит более громоздко чем с миксинами, и правки в такие матрешки вносить, имхо, труднее.

Я понимаю, что пример достаточно надуманный, более реальный мне как-то затруднительно привести, надо думать. Но мысль я думаю ясна, и в реальной жизни я думаю такое вполне себе встречается

При этом, нужно понимать, что аналогичная проблема, в целом, есть и у миксинов, и с какой-то точки зрения, она даже страшнее, ведь миксины не создают явного наследования, но при этом все ещё создают зависимость.

А в чем проблема то? Ну да, явного наследования нет, но зависим от миксина, что в этом плохого то? То что зависим не от абстракции? В наследовании мы тоже можем зависеть не от абстракции, при паттерне шаблон-стратегия. В общем, не вижу тут проблемы 😄

Sign up to leave a comment.

Articles