Каковы некоторые хорошие примеры Mixins и или Черты? - PullRequest
15 голосов
/ 10 декабря 2008

Я читал о Ruby и узнал о его миксин-паттерне, но не мог придумать много полезных миксин-функций (потому что я не привык так думать, скорее всего). Поэтому мне было интересно, что было бы хорошим примером полезной функциональности Mixin?

Спасибо

Редактировать: немного фона. Я прихожу из C ++ и других объектных языков, но я сомневаюсь, что Ruby говорит, что он не наследует миксины, но я продолжаю видеть миксины как множественное наследование, поэтому я боюсь, что слишком рано классифицирую их в своей зоне комфорта и не совсем грок, что такое миксин.

Ответы [ 4 ]

12 голосов
/ 10 декабря 2008

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

В стандартной библиотеке есть несколько примеров:

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

Comparable - если вы включите этот модуль в класс, определения метода <=>, который сравнивает текущий экземпляр с другим объектом и говорит, что он больше, достаточно для обеспечения <, <=, ==,> =, > а между? методы.

Enumerable - смешивая в этом модуле и определяя каждый метод, вы получаете поддержку для всех других связанных методов, таких как сбор, внедрение, выбор и отклонение. Если у него также есть метод <=>, он также будет поддерживать сортировку, min и max.

DataMapper также является интересным примером того, что можно сделать с помощью простого оператора включения, взятия стандартного класса и добавления возможности сохранения его в хранилище данных.

9 голосов
/ 10 декабря 2008

Ну, обычный пример, который я думаю, это настойчивость

module Persistence
    def load sFileName
            puts "load code to read #{sFileName} contents into my_data"
    end
        def save sFileName
        puts "Uber code to persist #{@my_data} to #{sFileName}"
    end

end

class BrandNewClass
    include Persistence
    attr :my_data

        def data=(someData)
        @my_data = someData
    end
end

b = BrandNewClass.new
b.data = "My pwd"
b.save "MyFile.secret"
b.load "MyFile.secret"

Представьте, что модуль написан ниндзя Ruby, который сохраняет состояние вашего класса в файле.
Теперь предположим, что я пишу новый класс, я могу повторно использовать функциональность персистентности, смешав ее, сказав include ModuleILike. Вы даже можете включить модули во время выполнения. Я загружаю и сохраняю методы бесплатно, просто смешивая их. Эти методы такие же, как те, что вы написали сами для своего класса. Код / Поведение / Функциональность - повторное использование без наследования!

Итак, что вы делаете, это добавляете методы в таблицу методов для вашего класса (буквально не правильно, но близко).

3 голосов
/ 10 декабря 2008

В ruby ​​причина, по которой миксины не являются множественным наследованием, заключается в том, что комбинирование методов миксина - это разовая вещь. Это не будет такой большой проблемой, за исключением того, что модули и классы Ruby открыты для модификации. Это означает, что если вы смешаете модуль с вашим классом, а затем добавите метод к модулю, метод не будет доступным для вашего класса; где, если бы вы сделали это в обратном порядке, это было бы.

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

Когда вы include модуль в ruby, он вызывает Module#append_features на этом модуле, который добавляет копию методов этого модуля один раз.

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

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

Возможно, вы могли бы изменить модуль ruby ​​'include', чтобы он действовал больше как множественное наследование, изменив Module#append_features, чтобы сохранить список включений, а затем обновить их с помощью обратного вызова method_added, но это будет Значительно отличается от стандартного Ruby и может вызвать серьезные проблемы при работе с чужим кодом. Возможно, вам лучше создать метод Module#inherit, который будет вызывать include и обрабатывать делегирование.

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

1 голос
/ 10 декабря 2008

Он широко используется, поскольку можно использовать множественное наследование в C ++ или реализовать интерфейсы в Java / C #. Я не уверен, где лежит ваш опыт, но если вы уже делали эти вещи раньше, миксины - это то, как вы делали бы их в Ruby Это систематизированный способ внедрения функциональности в классы.

...