Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
(defmethod canFireball (get-grid-node {:magic :fire, :limbs :hands} #'grid) [p] (> (:mana p) 0))
; владеющие магией огня и имеющие рука - пускают, если есть мана.
!func can
doc =владеющие магией огня и имеющие рука - пускают, если есть мана.
>
action fireball
obj
magic fire
limbs hands
mana int
power int
< is-desc
obj/mana
power
!obj alice
descr =Алиса - это слабенький такой маг огня
magic fire
limbs hands
mana int =10
# выводим в консоль может ли Алиса кинуть минимальный огненный шар
< can
action fireball
obj alice
power int =5
(def FireHands (get-grid-node {:magic :fire, :limbs :hands} #'grid))
(defmethod canFireball FireHands [p] (> (:mana p) 0))
(def simpleMage (withMeta {:grid-hierarchy-cache FireHands} {:mana 100}))
(defmacro def-grid-node [name props grid] ...)
(def-grid-node FireHands {:magic :fire, :limbs :hands} #'grid)
(defmethod canFireball FireHands [p] (> (:mana p) 0))
(def simpleMage (->FireHands {:mana 100}))
Но наборы свойств со временем становятся очень большими, начинают пересекаться нетривиальным образом.
Внести изменения в глубине иерархии становится проблематично, приходится думать заранее о «внедрении зависимостей», разрабатывать и использовать сложные инструменты рефакторинга.
Возможно ли всего этого избежать?
раса магия конечности материал есть ручка для переноски?
маг маг огонь руки - -
варвар человек - руки - -
феникс маг огонь крылья - -
эльф эльф воздух руки - -
чайник - - - железо да
тарелка - - - фарфор нет
голем голем - руки железо -
Возможно ли всего этого избежать?Да, и вы на самом деле движетесь в правильную сторону. Но деле в том, что это всё уже сделано за нас. Computer Science, благо, не стоит на месте. Современные языках программирования (Rust, Haskell, Swift, Scala и пр.) предоставляют более элегантные средства полиморфизма, чем традиционное для ООП наследование (которое вобще анти-паттерн и заноза в заднице). Рекомендую ознакомится с концепцией тайпклассов.
(defmethod canFire (get-grid-node {} #'grid) [p] false)
; огнем, поумолчанию, ни кто не владее
(defmethod canFire (get-grid-node {:limbs :hands} #'grid) [p] true)
; рукастые могут развести огонь
(defmethod canFire (get-grid-node {:magic :fire} #'grid) [p] (> (:mana p) 0))
; владея магией руки иметь не обязательно
(defmethod canFire (get-grid-node {:magic :fire, :limbs :hands} #'grid) [p] true)
; магия и руки совместимы - Clojure боится перепутать причину, по которой дано это свойства
Такое наследование я уже пробовал реализовать на Common Lisp. Но устройство MOP я не знаю, и та реализация не встроена в CLOS и не слишком эффективна.А вам не диспетчеризация по предикату нужна? Если её прикрутить в CLOS, то там можно выразить какие угодно условия для применения методов.
(defpmethod can-fire? ((char <character>))
(:when (eq 'hands (limbs char)))
t )
Этот метод can-fire? будет вызываться, если ей передадут экземпляр класса <character>, у которого в слоте limbs лежит значение hands. Иначе этот код вообще не будет выполнен и управление пойдёт к следующему потенциально применимому методу.
Решетчатое наследование