9
12

Роли и наследование

ivanych
2015-03-18 17:39

Модули Moose, Moo etc используют так называемые «роли». Утверждается, что роли - это альтернатива наследованию.

Не могу понять суть этого явления. Для чего нужны роли? Почему не обойтись наследованием через extends?

У меня сложилось впечатление, что роли преследуют некую академическую цель, мол "множественное наследование это плохо, по возможности избегайте". Но есть ли практический смысл?

Вроде бы пользы никакой, наоборот, только мешает.

К примеру, есть классы "Здание" и "Общественное заведение". Используя множественное наследование мы можем сделать класс "Ресторан". А еще можем сделать экземпляр класса "Здание" и использовать Здание само по себе - к празднику украшать.

А если "Здание" и "Общественное заведение"- это роли? "Ресторан" мы сделаем, но вот Здание само по себе уже не можем использовать. Но ведь это же неудобно, Здание может понадобиться по отдельности, заранее ведь не угадаешь. Объявишь его ролью - и все, привет, к празднику его уже не украсишь, пока в нем Ресторан не разместится.

Зачем тогда нужны роли?

  • vti
    2015-03-18 18:13 #

    Множественное наследование и наследование в частности обладает практическими недостатками.

    Например, непонятно чей конструктор наследовать. Классы не так просто компоновать, потому как порядок тут имеет значение. Может возникнуть неопределенность при резолвинге методов, нужно использовать Class::C3 или подобные.

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

    Мне кажется, что роли это как use strict для множественного наследования :)

    или CTRL+Enter формат
    • ivanychvti
      2015-03-18 20:45 #

      Аналогия с use strict понятна. Т.е. я понимаю, какой будет эффект, если класс объявить ролью.

      Но я не понимаю, зачем это надо. Конструктор я задам явным образом, методы назову уникально. И всё - вроде бы больше роль низачем и не нужна.

      В каком случае мне следовало бы объявить класс "Здание" ролью? Какое соображение должно оказаться более важным, чем потеря возможности сделать экземпляр Здания?

      или CTRL+Enter формат
      • vtiivanych
        2015-03-19 05:30 #

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

        Если Здание делать ролью, то лучше это назвать по поведению, например, МожноПогреться. Тогда в классе Здание можно использовать роль МожноПогреться и пользоваться им совершенно спокойно.

        Получаются роли: МожноПогреться, МожноЗайти, МожноПоесть. И классы, которые используют эти роли Здание (with МожноПогреться), Общественное заведение (with МожноЗайти) и Ресторан (with МожноПогреться, МожноЗайти, МожноПоесть).

        Т.е. сами классы разделены, а роли можно комбинировать.

        или CTRL+Enter формат
  • vti
    2015-03-18 18:16 #

    Детальная статья с примерами про недостатки наследования и Роли как альтернатива http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf.

    1
    или CTRL+Enter формат
  • ash
    2015-04-06 10:01 #

    Рекомендуют делать наследование там, где производный класс "является" (is) чем-то, а добавлять роли, когда он "делает" (does) что-то :-)

    Class dog is animal does bark;

    Class bird is animal does fly;

    То есть понятие животного есть как таковое, а самого по себе "лающего животного" -- нет. Умение лаять это способность, поэтому это роль.

    Хотя действительно это часто очень тонкая и неоднозначная грань.

    или CTRL+Enter формат
Чтобы ответить, залогиньтесь или зарегистрируйтесь.
  • @user
  • _italic_

    italic

  • **bold**

    bold

  • [PP](http://pragmaticperl.com)

    PP

  • <http://pragmaticperl.com>

    http://pragmaticperl.com

  • module:Plack

    Plack

  • release:URI

    URI

  • author:VTI

    VTI

  • `my $foo = 'bar'`
  • ```
    my $multi;
    $line;
    ```