Как разморозить сломанное заклинание

предыдущая серия

Наследование

В прототипном наследовании при обращении к свойству сперва смотрится наличие этого свойства в «локальном» объекте, и если оно в нем отсутствует, тогда проверяется родительский объект, и так далее выше по цепочке. Если же родителя нету, вернуть null.

Простейший способ реализации — как уже говорилось, зарезервировать некоторые названия свойств, а в частности, «parent», который будет указывать на родителя. Компактно этот подход можно закодировать рекурсией, однако Стив предупреждает, что наследование свойств — одно из узких горлышек нашего паттерна, поэтому лучше пробегать по родителям итеративно.

При желании можно реализовать и множественное наследование. Тогда свойство parent должно иметь тип «список», а уж каким способом выбирать родителя из списка, определяется конкретной реализацией.

Удаление

Когда мы удаляем свойство объекта в ситуции, когда наследование не поддерживается, достаточно просто удалить пару ключ-значение из списка свойств. Если же удаляемого свойства нету, надо вернуть корректный результат «свойство отсутствует».

В ситуации, когда у объекта есть родитель, возникает ряд неоднозначностей. Например, у нас есть объект А, наследник-прототип объекта Б. У объекта Б есть свойство «абв», но у объекта А его нету. Мы удаляем свойство «абв» у объекта А (где оно отсутствует), но очевидно не имеем права удалять его из вышестоящего объекта Б. В таком случае удаление может формально выполнится, однако свойство «абв» у объекта Б все равно останется (как наследуемое от родителя). Не очень удобный, но пожалуй единственный способ решения этой проблемы — возвращать специальный результат «не найден, но имеется у родителей».

Асимметрия записи/чтения

Когда мы считываем значение свойства, оно при необходимости вытаскивается из цепочки наследования. Но как быть с записью свойства в объект, в котором это свойство отсутствует, а присутствует лишь у родителя? Очевидно, тут надо создать его экземпляр непосредственно в «локальном» объекте, к которому происходит прямое обращение.

Только для чтения

Некоторые свойства желательно иметь неизменяемыми, для чего можно, например, помечать их специальным признаком read_only. В таком случае наследование их надо запретить.

Переходные свойства

Стив приводит интересный пример из практики своей игры Wyvern: игрок кастит заклинание «сопротивление магии», которое повышает его соответствующее сопротивление на 30%. Далее автосейв сохраняет это состояние в базе, после чего игра по какой-то причине падает. В результате игрок на халяву получает фиксированное сопротивление +30%! Причем причиной этого может стать не крэш, а любой сетевой сбой, исключение в коде итд.

Временное решение, которое придумал Стив, такое: у каждого объекта две копии списка свойств — одно для постоянных, другое для переменных (изменяющихся на ограниченное время). Вторая копия в базу не записывается. В некоторых случаях переменные свойства могут переопределять постоянные (например, способность видеть в темноте исходно недоступна, но после употребления зелья на какое-то время включается — переменное свойство получает противоположное значение). Здесь довольно много нюансов: например, на постоянное значение может воздействовать сразу несколько модификаторов (игрок кастует несколько заклинаний), и не всегда очевидно, как их сумммировать. Есть проблема и с удалением свойства: если задействовано на какое-то время переходное свойство, удалять постоянное свойство некорректно. В таком случае придётся возвращать еще один вид результата отказа в удалении.

Мне тут кажется гораздо более приемлемым функциональный подход: мы храним постоянное свойство и набор текущих модификаторов для него, а «изменяющееся» свойство просто вычисляем динамически на основании этих модификаторов при каждом к нему обращении. Недостаток — в некотором нагрузочном оверхеаде.

продолжение

Поделиться статьей ...Share on Facebook0Share on Google+0Tweet about this on TwitterShare on LinkedIn0Share on VKPrint this page

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *