«Банда четырех» ошибалась, стандартная библиотека Ruby неверна, и Rails тоже.
Но разве что-то не так, если все так делают? Да.
Книга «Банда четырех».
Шаблоны проектирования " дает нам общий словарь для понимания основных шаблонов ООП.
Это помогает нам использовать одну и ту же терминологию при обсуждении программного обеспечения.
К сожалению, это также вызывает путаницу.
Говорят: «состав до наследования».
Отлично, это имеет смысл.
Они говорят: «Используйте делегирование».
Большой.
Хотя в книге нет ни одного примера делегирования.
Делегирование — это метод, обеспечивающий гибкость программ.
Обычно говорят, что делегирование — это способ достижения композиции.
Но делегирование – это не то, что вы думаете, и «Банда четырех» ввела вас в заблуждение.
Хуже того, почти все упоминания о делегировании относятся только к объектам, работающим вместе и пересылающим сообщения.
Это примеры вызова методов, а не делегирования.
Наверняка ваш учитель программирования скажет вам, что вам необходимо хорошо понимать основные концепции программирования.
И понимать их правильно.
Так что же такое делегирование?
Делегирование легко понять — но давайте исправим тот факт, что мы постоянно видели этот термин вместе с описанием чего-то другого.Генри Либерман подробно описал этот термин в статье «Использование прототипных объектов для реализации общего поведения в объектно-ориентированных системах».
Но я вас к этому не отсылаю, хотя это будет полезно читать (или ее онлайн вариант ) — Я даю ключевой момент, который описывает делегирование.
Либерман обсуждал эту проблему в контексте инструмента рисования с графическим интерфейсом.
Вот основная идея: Когда перо делегирует сообщение о рисовании прототипу пера, оно говорит: «Я не знаю, как обработать сообщение о рисовании.
Пожалуйста, ответьте, если можете, и если у вас есть еще вопросы, например, каково значение x или вам нужно сделать что-то еще, вам нужно будет вернуться ко мне и спросить».
Если сообщение дополнительно делегируется, все вопросы о значении переменных или запросы ответов на сообщения передаются объекту, который первоначально делегировал сообщение.
То есть, когда вы отправляете сообщение объекту, у него есть концепция «я», в которой он может найти атрибуты и методы.
Когда этот объект делегирует полномочия другому, каждая ссылка на себя всегда указывает на исходный объект. Всегда.
Другое наследство
Наследовать можно не только от классов.Наследование на основе прототипов — это еще один способ организовать объекты таким образом, чтобы они могли иметь общее поведение.
Один подход устанавливает поведение в абстрактном месте (классе), а другой — в экземплярах (объектах).
Себя — язык программирования, реализующий то, о чем говорит Либерман.
У Self есть объекты, содержащие слоты.
Каждый слот может содержать метод или ссылку на объект-прототип в родительском слоте.
Если объект получает сообщение и не понимает его, он может делегировать его объекту в родительском слоте.
Это наследование прототипов, а не классов.
Это примерно такое же, хотя и не идентичное, поведение, когда у объекта есть класс (например, объекты Ruby), содержащий дополнительное поведение.
Предоставление объектам родительских слотов в Self аналогично предоставлению в JS объект со ссылками на прототипы.
JS — самый популярный язык прототипирования, и его гораздо проще опробовать.
Поэтому не будем изучать Self, а сразу попробуем JS. Следующий код можно даже выполнить непосредственно в консоли браузера.
В JS можно назначить прототип — эквивалент родительского слота в Self.
В контексте делегирования объект сегмента — это клиент, пересылающий сообщение делегату.function Container(){}; Container.prototype = new Object(); Container.prototype.announce = function(){ alert("these are my things: " + this.things) }; function Bucket(things){this.things = things}; Bucket.prototype = new Container(); bucket = new Bucket("planes, trains, and automobiles") bucket.announce() // alerts "these are my things: planes, trains, and automobiles"
В нашем примере вы можете видеть, что оценка this.things происходит в контексте клиентского объекта.
Когда мы вызываем анонс, он находится в объекте делегата.
При оценке функции это указывает на клиента.
Когда прототип объекта в JS имеет функцию, она оценивается так, как если бы у объекта был такой метод. Первый пример показывает, что this (в JS это self) всегда указывает на исходного получателя сообщения.
Как это в Руби?
Во-первых, давайте посмотрим на пересылку сообщений.Пересылка — это передача сообщения от одного объекта к другому.
Пересылаемая стандартная библиотека называется так и позволяет пересылать сообщения от одного объекта к другому.
Давайте теперь возьмем библиотеку делегатов с не столь удачным названием, которая также позволяет пересылать сообщения от одного объекта к другому.
require 'delegate'
# assuming we have a Person class with a name method
person = Person.new(:name => 'Jim')
class Greeter < SimpleDelegator
def hello
"Hi! I'm #{name}.
"
end
end
greeter = Greeter.new(person)
greeter.hello #=> "Hi! I'm Jim."
Что происходит внутри Гритера? Когда его экземпляр инициализируется, он содержит ссылку на person. Когда вызывается неизвестный метод, он перенаправляется целевому объекту (а именно, человеку).
В конце концов, мы все еще работаем с библиотекой делегатов, которая помогает нам с пересылкой сообщений.
Смущенный? И я тоже был в замешательстве.
Как и весь остальной мир, видимо.
Пересылка — это просто пересылка сообщения объекту — вызов метода.
Разница между этим и делегированием в том, что эти библиотеки позволяют легко передавать сообщения дополнительным объектам, а не просто вызывать метод другого объекта в контексте первого, как в случае с наследованием прототипов в JS. Обычно мы об этом не задумываемся, потому что возможности Ruby Method_missing делают свое дело внутри SimpleDelegator. И мы думаем, что методы волшебным образом вызываются на нужном объекте.
И хотя наш Greeter ссылается на себя, когда у клиента нет необходимого метода, сообщение отправляется другому объекту и обрабатывается там.
Если нам нужно поделиться поведением, не расширяя объект дополнительными методами, то могут помочь метод_missing и/или SimpleDelegator. Для простых вариантов это работает хорошо.
Но эта система нарушает ссылку на класс объекта.
Допустим, нам нужно сослаться на класс клиентских объектов с каким-то новым типом приветствия.
Вместо обычного скажем: «Привет! Я уважаемый человек, Джим.
Мы не будем переписывать метод, а просто полагаемся на super, чтобы получить то, что определено в обычном классе Greeter. class ProperGreeter < Greeter
def name
"the esteemed " + self.class.name + ", " + super
end
end
proper_greeter = ProperGreeter.new(person)
proper_greeter.hello #=> "Hi! I'm the esteemed ProperGreeter, Jim."
Получилось немного не так, как мы хотели.
Мы хотели увидеть «уважаемого Человека».
Это простой пример того, что на самом деле у нас есть два объекта, и как в ООП начинается шизофрения из-за себя.
Каждый объект имеет свою индивидуальность и свое понимание себя.
Мы можем исправить ситуацию, изменив ссылку на __getobj__ (как этого ожидает SimpleDelegator) вместо self, но это пример того, как self не ссылается на то, что нам нужно.
Нам приходится работать с двумя объектами, и наше понимание того, как работает программа, требует от нас думать о двух объектах, взаимодействующих друг с другом, в то время как мы, по сути, меняем поведение только одного.
Это не делегирование, а взаимодействие двух объектов.
Несмотря на кучу статей, книг и библиотек, которые убеждают вас в обратном.
Ну, давайте называть это как хотите
Какая разница – все так делают? Да, «Шаблоны проектирования» содержат примеры на C++.А C++ не умеет делегировать.
Достаточно ли этого аргумента, чтобы переопределить значение этого термина? Если язык, который вы используете, не обладает такой способностью, не говорите, что он может «делегировать».
Исправление концепций
Для разработки приложения необходимо понимать не только понятия логики его работы, но и владеть различными инструментами и подходами к архитектурной разработке.Шаблоны проектирования программного обеспечения — это распространенные способы решения общих проблем.
Понимание того, как они работают и когда их использовать, является одним из ключевых качеств успешного разработчика.
Книга «Банда четырех шаблонов проектирования» дает нам общий словарь для понимания основных шаблонов ООП.
Это помогает нам использовать одну и ту же терминологию при обсуждении программного обеспечения.
Когда я начал исследования для написания книги Чистый Рубин , я обратился к шаблонам проектирования.
«Наверняка эта книга поможет сформировать правильное понимание использования разных шаблонов», — подумал я.
К сожалению, в нем содержится грубая ошибка, которая повторена в огромном количестве книг, статей и библиотек.
«Шаблоны проектирования» хорошо продвигают идею «композиции перед наследованием».
Эта фраза нравится столь многим людям, что в следующий раз, когда вы будете обсуждать наследование классов, вам, вероятно, ударят по голове.
«Шаблоны проектирования» часто хвалят не за новаторство, а за консолидацию терминов.
Он помогает нам использовать язык, который мы используем для понимания и обсуждения различных методов решения проблем.
Она дала названия общим закономерностям, чтобы мы могли более продуктивно общаться друг с другом.
К сожалению, эти похвалы оказываются неуместными, как только вы попытаетесь понять делегирование.
Моя книга «Чистый Руби» углубляется в понимание делегирования и исследует возможности того, как правильно организовать ваши проекты, сделать их легко поддерживаемыми и слабосвязанными.
Он дает вам способы организовать разделение поведения и уточняет определение важных понятий.
Теги: #делегирование #наследование #ruby #JavaScript #программирование #дизайн и рефакторинг #ruby на рельсах
-
На Марсе Нашли Не Только Воду.
19 Oct, 24 -
Как Я Веду Себя На Сайте Фриланса
19 Oct, 24 -
Подробное Руководство По Вскрытию
19 Oct, 24 -
Работа С Com-Портом В Веб-Проекте
19 Oct, 24