Я знаю, что в Ruby нет концепции абстрактного класса. Но если это вообще нужно реализовать, как это сделать? Я пробовал что-то вроде ...
class A
def self.new
raise 'Doh! You are trying to write Java in Ruby!'
end
end
class B < A
...
...
end
Но когда я пытаюсь создать экземпляр B, он вызывает внутренний вызов, A.new
который вызовет исключение.
Кроме того, модули не могут быть созданы, но и унаследованы. сделать новый метод закрытым также не будет. Есть указатели?
ruby
abstract-class
Chirantan
источник
источник
raise "Doh! You are trying to write Java in Ruby"
,Ответы:
Мне не нравится использовать абстрактные классы в Ruby (почти всегда есть способ лучше). Если вы действительно считаете, что это лучший метод в данной ситуации, вы можете использовать следующий фрагмент, чтобы более четко определить, какие методы являются абстрактными:
По сути, вы просто вызываете
abstract_methods
список методов, которые являются абстрактными, и когда они вызываются экземпляром абстрактного класса, возникаетNotImplementedError
исключение.источник
NotImplementedError
который, по сути, означает «платформенно-зависимый, недоступный в вашей». См. Документы .Я думаю, что нет причин мешать кому-либо создавать экземпляр абстрактного класса, особенно потому , что они могут добавлять к нему методы на лету .
Языки с утиной типизацией, такие как Ruby, используют наличие / отсутствие или поведение методов во время выполнения, чтобы определить, следует ли их вызывать или нет. Поэтому ваш вопрос, поскольку он применяется к абстрактному методу , имеет смысл
и это должно быть конец истории. Единственная причина использовать абстрактные классы в Java - настаивать на том, чтобы одни методы были «заполнены», в то время как другие имели свое поведение в абстрактном классе. В языке «утиного набора» основное внимание уделяется методам, а не классам / типам, поэтому вам следует переместить свои заботы на этот уровень.
В вашем вопросе вы в основном пытаетесь воссоздать
abstract
ключевое слово из Java, которое является запахом кода для выполнения Java в Ruby.источник
Попробуй это:
источник
#initialize
B, вы можете просто поднять все, что в A # initializeif self.class == A
.источник
для всех в мире рельсов реализация модели ActiveRecord как абстрактного класса выполняется с помощью этого объявления в файле модели:
источник
Мой 2 ¢: Я выбираю простой и легкий миксин DSL:
И, конечно, добавить еще одну ошибку для инициализации базового класса в этом случае было бы тривиально.
источник
err = NotImplementedError.new(message); err.set_backtrace caller()
YMMVЗа последние шесть с половиной лет программирования на Ruby мне ни разу не понадобился абстрактный класс.
Если вы думаете, что вам нужен абстрактный класс, вы слишком много думаете о языке, который их предоставляет / требует, а не о Ruby как таковом.
Как предлагали другие, миксин больше подходит для вещей, которые должны быть интерфейсами (как их определяет Java), а переосмысление вашего дизайна больше подходит для вещей, которым «нужны» абстрактные классы из других языков, таких как C ++.
Обновление 2019: мне не нужны абстрактные классы в Ruby за 16,5 лет использования. Все, что говорят все, кто комментирует мой ответ, решается путем фактического изучения Ruby и использования соответствующих инструментов, таких как модули (которые даже дают вам общие реализации). В командах, которыми я управлял, есть люди, которые создали классы с базовой реализацией, которая терпит неудачу (например, абстрактный класс), но это в основном пустая трата кода, потому
NoMethodError
что приведет к тому же результату, что иAbstractClassError
в производстве.источник
Вы можете попробовать 3 rubygems:
интерфейс
абстрактный
простой абстрактный
источник
Лично я возбуждаю NotImplementedError в методах абстрактных классов. Но вы можете оставить его вне «нового» метода по указанным вами причинам.
источник
initialize
методы не вызываются автоматически, если явно не вызваны с помощью super.Если вы хотите использовать неустановленный класс, в своем методе A.new проверьте, есть ли self == A, прежде чем выдавать ошибку.
Но на самом деле модуль больше похож на то, что вы хотите здесь - например, Enumerable - это то, что может быть абстрактным классом на других языках. Технически вы не можете разделить их на подклассы, но колл
include SomeModule
позволяет достичь примерно той же цели. Есть ли причина, по которой это не сработает для вас?источник
Какой цели вы пытаетесь достичь с помощью абстрактного класса? Возможно, есть лучший способ сделать это на рубине, но вы не указали никаких подробностей.
Мой указатель таков; используйте миксин, а не наследование.
источник
Другой ответ:
Это полагается на обычный #method_missing для сообщения о нереализованных методах, но предотвращает реализацию абстрактных классов (даже если у них есть метод инициализации)
Как было сказано на других плакатах, вам, вероятно, следует использовать миксин, а не абстрактный класс.
источник
Я сделал это таким образом, поэтому он переопределяет новое в дочернем классе, чтобы найти новый в не абстрактном классе. Я до сих пор не вижу практического смысла в использовании абстрактных классов в Ruby.
источник
Также есть эта маленькая
abstract_type
жемчужина, позволяющая ненавязчиво объявлять абстрактные классы и модули.Пример (из файла README.md ):
источник
В вашем подходе нет ничего плохого. Поднять ошибку при инициализации кажется прекрасным, если, конечно, все ваши подклассы переопределяют инициализацию. Но вы не хотите так определять self.new. Вот что бы я сделал.
Другой подход заключался бы в том, чтобы поместить всю эту функциональность в модуль, который, как вы упомянули, никогда нельзя внедрить. Затем включите модуль в свои классы вместо наследования от другого класса. Однако это сломало бы такие вещи, как супер.
Так что это зависит от того, как вы хотите его структурировать. Хотя модули кажутся более чистым решением для решения проблемы «Как мне написать что-то, что предназначено для использования другими классами»
источник
Двухстрочный гем: https://rubygems.org/gems/abstract
источник
Хотя это не похоже на Ruby, вы можете сделать это:
Результаты:
источник