Гибкий шаблон декоратора?

Я искал шаблон для моделирования того, что я думаю сделать в личном проекте, и мне было интересно, будет ли работать модифицированная версия шаблона декоратора.

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

Есть ли у кого-нибудь опыт использования шаблона декоратора таким образом? Или я лаю не на то дерево?

Пояснение

Чтобы объяснить «промежуточные декораторы», если, например, мой базовый класс - это кофе, украшенный молоком, который украшен сахаром (на примере шаблонов дизайна Head first), молоко будет промежуточным декоратором, поскольку оно украшает базовый кофе и украшается по сахару.

Еще одно уточнение :)

Идея состоит в том, что предметы меняют характеристики, я согласен, что я впихиваю в это декоратор. Я загляну в государственную сумку. по сути, я хочу иметь единую точку доступа к статистике и для того, чтобы они поднимались/опускались, когда предметы экипированы/не экипированы.

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

Я просто ищу отзывы здесь, я знаю, что я мог бы использовать бензопилу, где ножницы были бы более подходящими...


person Omar Kooheji    schedule 09.10.2008    source источник
comment
что вы подразумеваете под промежуточными декораторами?   -  person cruizer    schedule 09.10.2008


Ответы (8)


Честно говоря, это звучит так, как будто вы действительно пытаетесь подогнать шаблон там, где он вам на самом деле не нужен, просто ради использования шаблона. Не будь тем парнем.

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

person Joe Phillips    schedule 09.10.2008
comment
Идея заключалась в том, чтобы предметы могли влиять на любые характеристики. Вот почему я пошел за декоратором. - person Omar Kooheji; 09.10.2008

Я понимаю, что вы пытаетесь сделать, но одна вещь, которую нужно помнить о шаблонах, заключается в том, что вы не должны пытаться подгонять свой дизайн под шаблон. Шаблоны возникают естественным образом - поведение, которое вы описываете, на самом деле не является частью шаблона декоратора.

С учетом сказанного, я предполагаю, что вы захотите снять оружие с помощью какого-то уникального идентификатора, скажем:

Character.unequip(LIGHTSABER);

Если вы попытаетесь вписать это в шаблон декоратора, вам придется отслеживать экипированные в данный момент предметы, а затем, после удаления оружия, вам придется обновить ссылку на объект, украшающий СВЕТОВОЙ МЕЧ, на тот, который СВЕТОВОЙ САБЕР украшает. Это много работы.

Вместо этого, возможно, стоит рассмотреть идею @Mitch и позволить оружию персонажа помочь в сумке с имуществом. Помните, что у персонажа ЕСТЬ набор оружия. Мне кажется, что композиция может быть выходом.

person Tom    schedule 09.10.2008

Есть три ответа на реализацию распространяемой статистики в видеоигре:

(1) это удовлетворит любую любительскую игру, которую вы когда-либо будете делать (и практически любую профессиональную игру):

character.GetStrength() {
  foreach(item in character.items)
    strFromItems += item.GetStrengthBonusForItems();
       foreach(buff in character.buffs)
    strFromBuffs += buff.GetStrengthBonusForBuffs();
  ...

  return character.baseStrength + strFromItems + ...;
}

(обратите внимание, что разные функции GetStrength*() не имеют ничего общего друг с другом)

(2) это удовлетворит все игры, в названии которых нет слова «diablo»:

 character.GetStr() { ... // same as above, strength is rarely queried }
 character.GetMaxHP() { 
   if (character._maxHPDirty) RecalcMaxHP();
   return character.cachedMaxHP;
 }
 // repeat for damage, and your probably done, but profile to figure out
 // exactly which stats are important to your game

(3) еще

 // changes in diablo happen very infrequently compared to queries, 
 // so up propegate to optimize queries.  Moreover, 10 people edit 
 // the stat calculation formulas so having the up propegation match 
 // the caculation w/o writing code is pretty important for robustness.

 character.OnEquip(item) {
     statList.merge(item.statlist);
 }

 character.GetStrength() {
     statList.getStat(STRENGTH);
 }

 statlist.getStat(id) {
     if (IS_FAST_STAT(id)) return cachedFastStats[id];
     return cachedStats.lookup(id);
 }

 statlist.merge(statlist) {
      // left for an exercise for the reader
 }

И, честно говоря, (3) было, вероятно, излишним.

person Jeff    schedule 11.10.2008

Хммм.. Я думаю, что, возможно, шаблон команды был бы хорошим решением этой проблемы. Вот что я имею в виду:

Это ваш класс персонажа:

Public class Character {

 //various character related variables and methods here...

 Command[] equipCommands;
 Command[] unequipCommands;

 public Character(Command[] p_equipCommands, Command[] p_unequipCommands) {

  equipCommands = p_equipCommands;
  unequipCommands = p_unEquipCommands;
 }

 public void itemEquiped(int itemID) {

  equipCommands[itemID].execute(this);
 }

 public void itemUnequiped(int itemID) {

  unequipCommands[itemID].execute(this);
 }
}

Вот несколько примеров команд:

public class SwordOfDragonSlayingEquipCommand implements ItemCommand{

 public void execute(Character p_character) {

  //There's probably a better way of doing this, but of the top of my head...
  p_character.addItemToInventory(Weapons.getIteM(Weapons.SWORD_OF_DRAGON_SLAYING));

  //other methods that raise stats, give bonuses etc. here...
 }
}

public class SwordOfDragonSlayingUnequipCommand implements ItemCommand{

 public void execute(Character p_character) {

  //There's probably a better way of doing this, but of the top of my head...
  p_character.removeItemFromInventory(Weapons.getIteM(Weapons.SWORD_OF_DRAGON_SLAYING));

  //other methods that lower stats, remove bonuses etc. here...
 }
}

Конечно, это всего лишь предложение и определенно открыт для обсуждения, я не говорю, что это лучший или единственный способ сделать это...

person Sandman    schedule 11.10.2008

Просто сохраните 2 набора характеристик, базовую статистику и эффективную статистику. Когда вы экипируете или снимаете предмет, добавьте или вычтите из эффективных характеристик, где это уместно. Тогда вам не придется просматривать список своего снаряжения каждый раз, когда вы хотите узнать, какова ваша статистика.

person Gerald    schedule 12.10.2008

Я знаю, что этот вопрос старый, но это может помочь кому-то еще, если не ОП. Прочтите эту статью, чтобы понять, как на самом деле нужно делать подобные вещи в играх (от одного из разработчиков, работавших над играми Tony Hawk):

http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/

Составьте свои сущности/игровые объекты. Для построения поведения сущностей в играх никогда, НИКОГДА не полагайтесь на наследование или на что-либо, что само по себе каким-либо образом зависит от наследования - это включает шаблон декоратора, как предлагалось в ОП. Вы будете связывать себе руки. Композиция — это путь.

person Engineer    schedule 24.03.2010

Вы ищете шаблон стратегии?

person Thomas Eyde    schedule 11.10.2008

Почему бы не закодировать оружие следующим образом:

1 = бензопила 2 = дробовик 4 = рельсовая пушка

Так что теперь сумма 6 может означать только то, что у персонажа есть дробовик и рельсотрон. Это краткое изложение, поэтому вам не нужно повторять список словаря оружия. Вам по-прежнему нужна какая-то конструкция для хранения оружия, но, по крайней мере, с таким подходом вы получите скорость. Это предполагает, что у вас может быть только одно оружие каждой категории, но много категорий одновременно.

person David Robbins    schedule 13.10.2008