【问题标题】:Flexible Decorator Pattern?灵活的装饰器模式?
【发布时间】:2010-09-16 05:39:54
【问题描述】:

我正在寻找一种模式来模拟我正在考虑在个人项目中做的事情,我想知道修饰器模式的修改版本是否可以工作。

基本上,我正在考虑创建一个游戏,其中角色属性通过他们装备的物品进行修改。装饰器堆叠其修改的方式非常适合这一点,但是我从未见过允许您删除中间装饰器的装饰器,当物品未装备时会发生这种情况。

有没有人以这种方式使用装饰器模式?还是我找错树了?

澄清

为了解释“中间装饰器”,例如我的基类是用牛奶装饰的咖啡,用糖装饰的牛奶(使用 Head first 设计模式中的示例)牛奶将是中间装饰器,因为它装饰了基础咖啡,并被糖装饰。

还有更多说明:)

这个想法是物品会改变统计数据,我同意我将装饰器硬塞到这个里面。我会查看状态包。本质上,我想要一个单点调用统计数据,并在装备/未装备物品时让它们上升/下降。

我可以将修改器应用于装备时的角色统计数据,并在取消装备时将它们回滚。或者每当要求统计数据时,遍历所有项目并计算统计数据。

我只是在这里寻找反馈,我知道我可能会使用电锯,而剪刀会更合适......

【问题讨论】:

  • 中间装饰器是什么意思?

标签: design-patterns decorator


【解决方案1】:

说实话,听起来你真的在尝试适应一种你并不真正需要的模式,只是为了使用模式。不要做那种人。

现在,如果武器给角色一些额外的力量/耐力/生命值或其他什么,那么可能值得考虑。但听起来你根本不会用这些来修改(或装饰)角色的属性。

【讨论】:

  • 这个想法是让物品能够影响任何统计数据。这就是我选择装饰师的原因。
【解决方案2】:

我明白你想要做什么,但关于模式要记住的一件事是,你不应该试图将你的设计硬塞进一个模式。模式是自然发生的——你所描述的行为并不是装饰器模式的一部分。

话虽如此,我想你会想通过一些唯一的 ID 来解除武器装备,比如:

Character.unequip(LIGHTSABER);

如果您尝试将其融入装饰器模式,则必须跟踪当前装备的物品,然后在移除武器后,您必须更新装饰光刃的对象的引用到 LIGHTSABER 正在装饰的那一台。工作量很大。

相反,也许值得考虑@Mitch 的想法,让角色的武器在财产袋中有所帮助。请记住,一个角色拥有一套武器。对我来说,似乎组合可能是要走的路。

【讨论】:

    【解决方案3】:

    在视频游戏中实现传播的统计信息有三个答案:

    (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) 这将满足所有标题中没有“暗黑破坏神”一词的游戏:

     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) 可能是矫枉过正。

    【讨论】:

      【解决方案4】:

      嗯.. 我想也许命令模式会是解决这个问题的好方法。这就是我的意思:

      这是你的角色类:

      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...
       }
      }
      

      当然,这只是一个建议,绝对可以讨论,我并不是说这是最好的或唯一的方法......

      【讨论】:

        【解决方案5】:

        只需保留 2 组统计数据,即您的基本统计数据和有效统计数据。当您装备或取消装备物品时,在适当的情况下从有效统计数据中添加或减少。这样您就不必每次想知道自己的统计数据时都遍历您的设备列表。

        【讨论】:

          【解决方案6】:

          我知道这个问题很老,但如果不是 OP,这可能会对其他人有所帮助。阅读这篇文章,了解在游戏中真正应该如何做这类事情(由参与托尼霍克游戏的开发人员之一):

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

          组合您的实体/游戏对象。为了在游戏中构建实体行为,永远,永远不要依赖继承,或者任何本身以任何方式依赖继承的东西——这包括 OP 建议的装饰器模式。你会束缚自己的双手。作曲才是王道。

          【讨论】:

            【解决方案7】:

            您在寻找策略模式吗?

            【讨论】:

              【解决方案8】:

              为什么不对武器进行如下编码:

              1 = 电锯 2 = 霰弹枪 4 = 轨道炮

              所以现在6的总和只能意味着角色拥有霰弹枪和轨道炮。这是一个快速摘要,因此您不必遍历您的武器字典列表。你仍然需要一些结构来容纳武器,但至少你会通过这种方法获得速度。这假定您只能拥有每个类别的一种武器,但同时拥有多个类别。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-05-07
                • 1970-01-01
                • 2018-04-10
                • 2012-02-04
                • 1970-01-01
                相关资源
                最近更新 更多