|
|
|||||
Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
|
Цитата:
Я с позволения задам ещё пару вопросов по проектированию. К сожалению, пока никакого чутья на это дело нет, и перед реализацией каждой даже самой проходной задачи приходится долго тупить на предмет того, в какой класс разместить код или вообще создавать новый класс и т.п. Рекомендации уважаемых Nooob и Wolsh - ощутимо помогают (хоть отчасти противоречат друг другу), то пока тоже не смогли успокоить мою душу. Уже кратко спрашивал, теперь постараюсь подробнее сформулировать суть моего вопроса и альтернатив. Продумывая игровых персонажей и их механики, вывел 3 группы: npc, ключевые npc и сам игрок. Количество свойств увеличивается от npc до игрока. Когда дошла очередь до проектирования классов, я нарисовал табличку, где в столбцы поставил эти группы, а в строки - свойства. А дальше ставил на пересечении галочки, используется ли данное свойство или нет. По итогу получился такой расклад: совсем небольшое количество базовых свойств попали во все три группы (имя, ID, пол и т.п.), некоторое количество оказалось уникальным для персонажа игрока, ещё небольшая группа оказалась общей для npc и ключевых npc, наконец, пачка уникальных свойств только для ключевых npc. Итого 4 "профиля вхождения". Они определили вот такую структуру наследования классов: Charactrer - базовые свойства, общие для всех персонажей | | | - Character_hero - главный герой | - Character_npc - общие свойства для неписей и ключевых неписей | - Character_npc_key - уникальные свойства для ключевых неписей Теперь смотрю на эту структуру и сомневаюсь, правильно ли я начал делать и чем мне это аукнется в скором времени. Свойств много, часть из них полностью повторяется, поэтому делать совсем независимые отдельные классы для каждой группы - точно не вариант. Что остаётся? Первое, оставить как есть сейчас, для расчётов игровой механики писать классы с абстрактными методами для каждого из подклассов персонажей, т.е. воспользоваться прелестями полиморфизма (или зря я столько книжек прочитал!). Но смущает, что во-первых, дерево наследование кривое получается (вопрос, повлияет ли этот факт на работу абстрактных методов и вообще, насколько подобный перекос допустим), плюс много писанины - по 3 подкласса на каждый класс с расчётами. При условии, что ни в близком, ни в отдалённом времени я не планирую вводить другие группы персонажей (для которых было бы как раз удобно добавить отдельных потомков), всё это выглядит перебором и необоснованным усложнением. Вторая альтернатива - забить на наследование, собрать все свойства в один класс Character, а для того, чтобы различать, кто есть ху, добавить в класс соответствующее свойство-указатель, типа "player", "npc" или "key_npc" и присваивать его при создании каждого нового персонажа. Избавляемся от всего головняка с наследованием, но обрекаем себя на добавление конструкции switch или подобной во все методы, различающиеся для групп персонажей. Наконец, третий вариант - оставить классы как они есть, но не париться с полиморфизмом, а делать единые классы с методами расчётов и проверять на старте, какой из подклассов персонажей поступил. В зависимости от того, кто это оказался, запускать соответствующие версии функций. Буду признателен за развёрнутый ответ. |
|
|||||
Нуб нубам
модератор форума
Регистрация: Jan 2006
Адрес: Бердск, НСО
Сообщений: 6,445
|
Цитата:
__________________
Reality.getBounds(this); |
|
|||||
Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
|
Ещё раз посмотрел. Не прав. Сам дурак.
|
|
|||||
Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
|
Друзья!
Я продолжил свои изыскания в проектировании классов будущей игры и возник новый вопрос. Появился он при переходе от базовых свойств персонажа к специфическим: которые выделяются для пола, профессии и т.п. Пусть условно для мужчин учитывается длина бороды, а для женщин - объём талии. У меня получилось следующее. Я создал новый класс Gender с единственным свойством genderID, которое может принимать значения 0 для женского пола и 1 для мужского, и унаследовал от него два класса GenderMale и GenderFemale. В первом соответственно свойство beardLength, во втором - waistVolume, плюс set- и get-методы для каждого. Тогда в классе персонажа Character добавился такой set-метод: public function set gender(newGenderID:uint):void //Пол { switch (newGenderID) { case 1: _gender = new GenderMale(newGenderID); break; case 0: _gender = new GenderFemale(newGenderID); break; default: throw new Error ("Пол персонажа может иметь значение 0-female или 1-male"); } } Вопрос такой. Чтобы задать либо получить значения свойства, связанного с полом, приходится писать такой код. Например, для нашей бороды: В классе Character: public function set beardLength(bewBeardLength:Number):void {_gender.beardLength = bewBeardLength; } Наконец, в GenderMale: Аналогично с get-методом. В принципе работает, но как-то чересчур громоздко выглядит. И этим активно не нравится. Если на каждое подобное свойство писать методы в трёх местах, то это получится мясо и фарш, а не код. Обращаться напрямую character._gender.beardLength тоже не выходит, т.к. переменная _gender объявлена как private и менять её статус не вижу никакого резона. в общем, need help. Заранее спасибо. |
|
|||||
Нуб нубам
модератор форума
Регистрация: Jan 2006
Адрес: Бердск, НСО
Сообщений: 6,445
|
1. Если у тебя в Gender объявлена function set beardLength() то она будет и у Женщин, так?
2. Зачем в конструкторы Мужского и Женского пола передается еще и идентификатор? Ты же не собираешься делать экземпляр Мужчины со значением "женщина"? Да вроде и switch не позволит. Тогда зачем? 3. Конвенции просят не называть параметр сеттера как Бог черепаху, но всегда просто "value". Почему так? Потому что название сеттера уже несет необходимый смысл, а если нет то это плохое название сеттера. Он принимает значение для свойства с этим названием — ведь он хоть и функция, но прикидывается свойством. Поэтому как-то еще глубокомысленно называть параметр, который станет этим самым свойством с этим самым названием как-то очень странно. Так же принято называть внутреннее хранилище (приватную переменную, к которой доступ через геттер/сеттер) точно так же, как геттер/сеттер (только с подчеркиванием), потому что она собственно и есть это самое СВОЙСТВО. У тебя, в частности, грубейшее нарушение этого принципа: есть сеттер gender типа uint, а свойство _gender имеет тип Gender. Таким образом у твоего характера снаружи "гендер" это просто число 1 или 0, а внутри это целый экземпляр Мужика с бородой и талией. Теперь о смысловой нагрузке. Я думаю ты и сам видишь, что вместо абстрагирования получилась какая-то каша. До тех пор, пока пол Характера не имеет значения, все прекрасно, ты можешь обращаться с ним как просто с Человеком. Но как только встает вопрос пола, начинается катавасия — тебе приходится протаскивать в класс Характер ВСЕ половые признаки, и мужские и женские, и совершенно непонятно зачем вообще был нужен класс Gender, да еще и с подклассами Джентельмен и Мадмуазель, если ВСЕ их свойства вынужден представлять класс Характер, и даже как транспортный дата-обжект (для обмена данными) эти гендеры использовать нельзя, ибо доступ к ним как объектам наглухо закрыт. Лично мне ошибкой видится именно эта паническая инкапсуляция Гендера. Надо открыть к нему доступ напрямую, а не прокидывать все сеттеры/геттеры в Характер. В чем смысл, если доступ к этим свойствам ВСЕ-РАВНО есть, только с бубном вокруг деревни. Скрывать надо то, что другим НЕ НУЖНО знать. В чем смысл сокрытия гендера, мне непонятно. Сама идея собирать какие-то свойства определенного назначения в отдельные блоки нормальная. Это используется в нативных классах, например такие свойства визуальных объектов как .filters или .transform, или .defaultTextFormat у TextField.
__________________
Reality.getBounds(this); |
|
|||||
Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
|
Wolsh, спасибо за очередную порцию ликбеза. Отвечаю по пунктам:
Цитата:
Цитата:
static private const HINTS:Object = { ("Intelligence" + GlobalValues.GENDER_MALE as String): ["умный", "дурак"], ("Intelligence" + GlobalValues.GENDER_FEMALE as String): ["умная", "дура"] } Цитата:
Хотя в контексте того, что ты написал далее, само наличие сеттеров и геттеров для гендера в классе Character вызывает вопрос. Цитата:
Теперь появилась проблема. Если раньше было легко по идентификатору вытащить значения свойства, написав character[propID], где строковая переменная propID содержит название соответствующей переменной в классе Character, например "intelligence", то теперь, указав в propID = "gender.beardLength", выдаёт ошибку Можно как-то подтянуть? Последний раз редактировалось Appleman; 23.09.2017 в 18:01. |
|
|||||
Нуб нубам
модератор форума
Регистрация: Jan 2006
Адрес: Бердск, НСО
Сообщений: 6,445
|
Цитата:
_textField.defaultTextFormat.bold = true; _textField.defaultTextFormat = _textField.defaultTextFormat; По поводу character[propID] — ну чтож, теперь надо считаться с тем что это свойства не Характера а Гендера, то есть character.gender[propID].
__________________
Reality.getBounds(this); |
|
|||||
Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
|
Цитата:
Цитата:
Цитата:
Что будет предпочтительнее? Вернее, чем будет определяться выбор того или иного варианта? |
|
|||||
Нуб нубам
модератор форума
Регистрация: Jan 2006
Адрес: Бердск, НСО
Сообщений: 6,445
|
Цитата:
Во второй строке вызывается сеттер самого TextField: "_textField.defaultTextFormat = " и ему отдается объект TextFormat, полученный из геттера _textField.defaultTextFormat. То есть тот самый объект, в котором значение свойства .bold теперь true. Cеттер это функция, она не просто присваивает этот ТекстФормат внутреннему хранилищу (он итак там лежит). Сеттер делает что-нибудь еще: считывает свойства переданного ему объекта ТекстФормат и "применяет" их "прямо сейчас". (может пример с ТекстФорматом и не совсем корректен ввиду того что там не требуется это "прямо сейчас", но вот если ты захочешь рычажком слайдера менять длину бороды в редакторе персонажа, то просто менять одно из свойств объекта Гендер будет недостаточно, чтобы видеть изменение в реальном времени). Цитата:
__________________
Reality.getBounds(this); |
|
|||||
Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
|
Цитата:
Мне тут ещё один вариант придумался. Может быть в классе AttributeHints первым делом выяснять, в каком классе "живёт" нужное нам свойство, и в зависимости от результата формировать обращение либо в character, либо в character.gender. Единственное, что смог найти, это метод hasOwnProperty(), но он работает только для классов типа Object. Есть ли что-то подобное для использования в своих классах? |
Часовой пояс GMT +4, время: 10:28. |
|
« Предыдущая тема | Следующая тема » |
|
|