Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Проверить на наличие геттера (http://www.flasher.ru/forum/showthread.php?t=215632)

Appleman 19.07.2018 15:42

Проверить на наличие геттера
 
Друзья, подскажите, пожалуйста, как проверить наличие в классе геттера, зная строку для обращения? Попытка написать:

Код AS3:

trace(SomeClass.hasOwnProperty(PropID))

выдаёт false, даже если геттер в нём прописан. Больше ничего дельного в голову не приходит.

СлаваRa 19.07.2018 18:20

Отказаться от использования столь ужасного подхода к программированию?

alexandrratush 19.07.2018 18:30

Какая задача стоит перед вами? Вам может помочь рефлексия.

СлаваRa 19.07.2018 21:23

Ну какая, вестимо поверить наличие геттера в объекте по строковому ключу.

Appleman 20.07.2018 10:04

Решил. Оказывается, если геттер не объявлен как public, то ничего не получается. Изначально был с модификатором internal.

Цитата:

Сообщение от СлаваRa (Сообщение 1205725)
Отказаться от использования столь ужасного подхода к программированию?

Это процесс не быстрый :)

СлаваRa 20.07.2018 10:29

Чем дольше вы тяните, тем масштабнее будут проблемы и демотивация, но я могу лишь советовать :)

Appleman 20.07.2018 12:38

СлаваRa, ко мне можно и нужно на "ты" :)

Я же не специально... У меня первый проект, я уже год делаю его для себя, в своё удовольствие и в меру собственных способностей. Расширение кругозора происходит стремительно, поэтому уже раза 2 почти полностью переписывал. И скорее всего, это не последний раз.

Если конкретно по обсуждаемому вопросу, но ноги растут вот отсюда. После того как я распихал многочисленные свойства класса Character по нескольким подключаемым классам, возникла проблема с обращениями к ним извне. Они у меня происходят через передачу строкового ID нужного свойства. Раньше я спокойно писал в любом месте, где есть ссылка на экземпляр персонажа: character[PropID], а теперь не могу, так как теперь свойство propID может быть как в самом классе Character, так и в Skills, Personality, Statuses и т.п.

На сегодня лучшее, что по этому поводу придумалось - это сделать единый метод, который будет проверять, где "живёт" запрашиваемое свойство, и выдавать его значение. Заодно применять к нему модификаторы, "подрезать" его при необходимости по установленному максимуму и т.п. Вот такой код:

Код AS3:

public function getProp (propID: String) : * // Возвращает значение свойства по ID
                {
                        if (this.hasOwnProperty(propID)) return this[propID];
 
                        var componentID: String = this.redirectByPropID(propID);
                        return this[componentID][propID];
                }
 
protected function redirectByPropID(propID: String) : String  // Возвращает ID компонента, хранящего свойство
                {
                        if (_personality.hasOwnProperty(propID)) return ChIDs.COMPONENT_PERSONALITY;
                        if (_parameters.hasOwnProperty(propID)) return ChIDs.COMPONENT_PARAMETERS;
                        if (_skills.hasOwnProperty(propID)) return ChIDs.COMPONENT_SKILLS;
 
                        throw (CLASS_DEBUG_NAME + "-> redirectByPropID: неизвестный ID параметра. Используйте константы класса ID персонажей!");               
                }

Если есть что покритиковать и предложить, буду признателен.

caseyryan 27.07.2018 22:09

Не обращая внимания на весь этот ужас в коде, все же спрошу)

А что если у тебя и _personality и _parameters будет содержать свойство propID?
Какое-то странное условие, мягко говоря.
И кстати, на сколько я помню, такая конструкция может легко отвалиться с ошибкой, если класс не динамический

Appleman 28.07.2018 00:15

Цитата:

Сообщение от caseyryan (Сообщение 1205746)
Не обращая внимания на весь этот ужас в коде, все же спрошу)

Ужас - в самом подходе или в его реализации? Не стесняйся, мне самому не нравится, но ничего лучше не придумалось пока.

Цитата:

А что если у тебя и _personality и _parameters будет содержать свойство propID?
Какое-то странное условие, мягко говоря.
Вообще такого быть не должно, так как я изначально разделил разные свойства персонажа на несколько блоков. Но теоретически, конечно, будет косяк, т.к. всегда будет возвращаться ссылка на первый проверяемый компонент.

Цитата:

И кстати, на сколько я помню, такая конструкция может легко отвалиться с ошибкой, если класс не динамический
Не, классы не динамические, всё работает. Главное, чтобы геттеры внутри имели модификатор public. Со всеми остальными hasOwnProperty выдаёт false.

СлаваRa 28.07.2018 00:51

с таким подходом не возможно:
- рефакторинг
- обнаружение синтаксисческих ошибок на этапе компиляции
- обнаружение ошибок логики(вопрос выше про совпадение имен)
- нормальная работа IDE
- ...

caseyryan 28.07.2018 17:31

Цитата:

Ужас - в самом подходе или в его реализации? Не стесняйся, мне самому не нравится, но ничего лучше не придумалось пока.
Не совсем понимаю что ты хочешь сделать, но если у тебя эти классы унаследорваны от разных базовых классов, но свойства должно присутствовать обязательно, то почему ты не используешь интерфейсы?

Appleman 29.07.2018 23:05

СлаваRa, caseyryan, согласен, подход - дерьмо.

Цитата:

Не совсем понимаю что ты хочешь сделать, но если у тебя эти классы унаследованы от разных базовых классов, но свойства должно присутствовать обязательно, то почему ты не используешь интерфейсы?
Да они вообще ни от чего не унаследованы. В каждом - пачка свойств, а также сеттеров/геттеров. Возможно, когда добавятся какие-то методы обработки, обязательные для всех компонентов, тогда и потребуются интерфейсы для пущей уверенности.

Давайте я попробую привести ещё пример и задать вопрос.

Изначально в классе Character были прописаны свойства из "досье", которые остаются неизменными (сила, интеллект), свойства, отслеживающих текущие параметры (энергия, ХП), скиллы. От такой огромной простыни (сами свойства, сеттеры/геттеры, методы обработки) у меня класс сильно "распух". Чтобы всё это хозяйство организовать, придумалось раскидать свойства не нескольким новым классам. Но возникла новая проблема. У меня происходит много обращений за значениями свойств, переданных как параметры. Наиболее типичный случай - класс проверки условий доступности игровых действий. Вот его пример:

Код AS3:

public class ACPropEquality extends ACEntity 
        {
                private var _value: * ;
 
                public function ACPropEquality(newOwnerID: String, newPropID: String, newValue: *)
                {
                        super(newOwnerID, newPropID);
                        _value = newValue;
                }
 
                override public function testCondition(action:ActionEntity) : Boolean
                {
                        super.getOwner(action);
                        return (_owner.getProp(_propID) == _value);
                }
        }

Получается, что под newPropID может быть свойство из досье, текущий параметр или скилл. Я рассуждал так, что другие классы не должны "знать" и "вникать", где конкретно в классе персонажа "живёт" запрашиваемый параметр, а просто передать ID свойства и получить назад текущее значение. В этом случае встаёт вопрос, как в самом Character идентифицировать, где искать свойство под полученным ID. Результат - как видели выше.

Или я вас не правильно понял, и главный объект критики - это подход, при котором запросы текущих значений свойств сделаны через их строковые идентификаторы?

СлаваRa 29.07.2018 23:56

Цитата:

Или я вас не правильно понял, и главный объект критики - это подход, при котором запросы текущих значений свойств сделаны через их строковые идентификаторы?
бинго!

Appleman 30.07.2018 15:52

Отлично! Друзья, я вам буду очень признателен за любую наводку на более "красивое" решение.

Я попытался максимально компактно и доходчиво сформулировать ниже, почему у меня активно применяются строковые ID.

Класс игрового действия состоит из 3-х компонентов: справочных данных (ActionData), а также 2-х персонажей, один из которых - "актор" (кто активно действует), а второй - "реципиент" (кто принимает эффект от действия). Вот смотрите кусочек класса ActionEntity:

Код AS3:

protected var _actionData: ADEntity;         // Данные выполняемого действия
protected var _actor: Character;                // Актор - активный участник, совершающий действие
protected var _recipient: Character;        // Реципиент - пассивный участник, получающий эффект от действия
 
public function ActionEntity(data: ADEntity, character1: Character, character2: Character = null)
                {
                        _actionData = data;
                        this.recognizeRoles(character1, character2);
                }

Обратите внимание, что если, например, действие рассчитано на одного персонажа (например, применить на себя какой-нибудь предмет), то в таком случае в конструктор будет передан один персонаж, который будет и актором, и реципиентом. С этим разбирается метод recognizeRoles(). Он запускается прямо в конструкторе и сохраняет полученных персонажей в абстрактных переменных _actor и _recipient.

ActionData (наследник класса ADEntity) - содержит "справочные" данные действия. Они неизменны, и теоретически их можно (и наверное нужно) вообще из кода перенести куда-нибудь, но сейчас не об этом. Важно, что там формулируются условия нескольких видов: критические (при их невыполнении действие не будет создано), видимости (действие не будет выведено игроку) и активности (действие будет неактивно). Вот как это сделано сейчас:

Код AS3:

public class ADEntity
{
        protected var _criticalConditions: Vector.<ACEntity> = new Vector.<ACEntity>;
        protected var _visibleConditions: Vector.<ACEntity> = new Vector.<ACEntity>;
        protected var _activeConditions: Vector.<ACEntity> = new Vector.<ACEntity>;
}

В каждом векторе - набор одновременно выполняемых условий - наследники класса ACEntity. В своём предыдущем сообщении я приводил код одного из его наследников - класса ACPropEquality, проверяющего свойство на равенство указанному значению.

Вот маленький кусочек кода, где создаётся действие рукопашной атаки:

Код AS3:

_act = new ADDoubleMelee(ActionIDs.MELEE); 
_act.criticalConditions = new <ACEntity>
        [
        new ACPropEquality(ActionIDs.OWNER_ACTOR, ChIDs.RPG_CLASS, ChIDs.CLASS_FIGHTER)
        ];

Загвоздка в том, что, будучи прописанными в классе ADEntity, условия "не знают" и "не могут знать", что за действующие лица попадут в конструктор ActionEntity. Как мне сформулировать необходимость проверки каких-то свойств экземпляров Character в классе, не имеющим на них ссылок. Вот я и выкрутился со строковыми идентификаторами.

В классе ActionEntity запуск проверки условий выглядит так:
Код AS3:

public function testVisibleConditions() : Boolean
{
        for each (var cond: ACEntity in this._actionData.visibleConditions)
        {
                if (!cond.testCondition(this)) return false;
        }
        return true;
}

Если сможете сказать, как в таком раскладе обойтись без использования строковых ID, я буду очень благодарен.

Добавлено через 21 час 11 минут
Посидел-подумал... Вот такой вариант проверки условий придумался без использования строковых идентификаторов.

Код AS3:

public class ConditionStrength 
        {
                private var _measureMin: Number;
                private var _measureMax: Number;
 
                public function ConditionStrength(measureMin: Number = 0, measureMax: Number = 0)
                {
                        _measureMin = measureMin;
                        _measureMax = measureMax;
                }
 
                public function testCondition(ch: Character) : Boolean
                {
                        if (ch.strength >= _measureMin && ch.strength < _measureMax) return true;
                        return false;
                }
 
        }

Что скажете?

Wormhole 04.08.2018 21:32

Не читал последнее сообщение, но
обращайся напрямую через компоненты, например: character.progression.xp

Либо создай псевдо-свойства в базовом классе с геттерами, которые будут вызывать геттеры соответствующего свойства в его компоненте

Добавлено через 3 минуты
Но на компоненты имеет смысл делить, когда есть еще и дополнительная функциональность, связанная с этими свойствами, иначе получаем запах "Data Object".
Если ее нет, но свойств слишком много, проверь принцип одной обязанности - класс должен отвечать только за что-то одно.
Например, раньше у меня класс игрока содержал две абсолютно несвязанные друг с другом части - представление прогресса игрока и его раскачки и представление игрока в бою (с хп, маной и т. д.). Потом я их разделил на два класса

GBee 06.08.2018 11:53

Вроде интерфейсы прям-таки и напрашиваются.


Часовой пояс GMT +4, время: 15:47.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.