Сначала пара слов о картинке. По запросу «object oriented programming» к гугл.картинкам она отдается на первой странице. Так-то.
Все мы с молоком матери впитали, что «еврибади из обжект», достаточно вспомнить о «mov ax dx
», который, согласно первым AI, переводится на русский язык как «двинул топором начальника штаба». Тем не менее, иногда хочется стройности. Особенно, когда твоя библиотека переживает очередной git push
, и ты понимаешь, что теперь обязательно найдется кто-нибудь, жаждущий вызвать Divider.new (UndividedObject.new)
.
Иными словами, если вам вдруг втемяшилось повторить функциональность OOP Fops, наподобие Java/.NET в вопрсах ограничения наследования — это можно. Но, пожалуйста, не нужно так делать. Вызов .respond_to?
всегда дешевле, понятнее и элегантнее мусора, который я готов вам показать:
module MyModuleSet
module MyModule
class InterfaceNotImplemented < NoMethodError
end
def self.included(clazz)
clazz.send(:include, MyModule::Methods)
clazz.send(:extend, MyModule::Methods)
clazz.send(:extend, MyModule::ClassMethods)
end
module Methods
def not_implemented(clazz, method = nil)
if method.nil?
caller.first.match(/in `(.+)'/)
method = $1
end
raise MyModule::InterfaceNotImplemented.new("#{clazz.class.name} is abstract ('#{method}' must be implemented.)")
end
end
module ClassMethods
def to_implement!(name, *args)
self.class_eval do
define_method(name) do |*args|
not_implemented(self, name)
end
end
end
end
end
class AbstractClass
include MyModule
to_implement! :method1, :method2
…
end
Это непотребство бросит исключение, если в наследнике не объявлены method1 и method2. Но.
Я настаиваю на том, что так делать не нужно. Не сто́ит тащить за собой в новую жизнь груз ошибок. Если приходится полагаться на чужой код, всегда лучше написать «respond_to?», чем городить никому не понятный и не нужный огород.
Я написал эту заметку, поскольку сам поддался соблазну сделать что-то подобное. Пусть она отдается в поиске по плохим практикам.
Автор: matiouchkine