【问题标题】:Design Pattern suggestion for Item Use from Inventory库存中物品使用的设计模式建议
【发布时间】:2015-11-16 09:38:10
【问题描述】:

不幸的是,因为我学校的面向对象软件工程项目,我正在使用 java 和 slick2d 制作冒险游戏。

我正在应用 MVC 架构,并通过从 ItemFactory 类中的 Tiled 映射文件中读取来创建项目。他们似乎很适合这种游戏。

游戏中有多个项目会影响游戏,尤其是角色。 (在此上下文中角色与玩家相同)

有一个字符模型,它有一个内部类 Inventory,它基本上由一个 ArrayList 项目组成。

字符控制器有一个名为 takeItem 的函数,它接受一个容器参数(即货架),该参数也有一个 ArrayList 项目,然后删除里面的内容并放入库存。

它有一个名为 useItem 的函数,它接受一个 int 索引并使用相应索引中的项目。

在那之前,一切都很好。

现在的主要问题是,这些物品有特定的用途。例如,生命药水增加角色的生命值,隐形药水使其隐形等。

为了维持一个好的设计,我可以如何以及在哪里对这些项目进行解释和附加功能?

到目前为止,我认为是这样的: 1-我没有向项目类添加任何功能。它只有 name、description 和 Enumerated ItemType 和 int power 2- 我在角色控制器的 useItem() 方法中做所有工作,即

if (itemBeingUsed.getType() == Common.ItemType.POTION)
    `characterModel.increaseHealth(itemBeingUsed.getPower())`

如您所见,这似乎很奇怪,因为角色控制器就像一个项目解释器。

3- 另一种方法可能是创建一个使用字符控制器的 ItemInterpreter 类。虽然这看起来更优雅,但它会让我在角色控制器中执行一堆不必要的功能,例如调用角色模型的 increaseHelth() 函数的“increaseCharacterHealth”函数等等。

另外一个可能的问题是我使用Character Controller的函数来使用物品,但是物品也可能会影响游戏,即减慢时间,但是Character Controller在游戏的类层次结构之下,无法访问Game/GameController功能。减慢游戏时间等似乎至少现在不是这种情况,所以看起来我可以在 CharacterController 类中使用 Items,但我想知道你的意见,如果它是一个好的设计或者什么可以更好。

一些清除问题的代码:(注意:它们不完整) 注意:我将 ItemType、Direction 等枚举类型放在所有类都通用的 Common 类中。

在 CharacterController 中使用 item 函数:

public void useItem(int index){ 
        Item item = ((Character)obj).inventory.takeItem(index);
        if (item != null) {
            if (item.getType() == Common.ItemType.POTION) {
                ((Character)obj).increaseHealth(item.getPower()); // I have extended a Person class, now I have to typecast to character everytime, which is also nonsense
            }
            else
                System.out.println("and other items..");
        }
        else
            System.out.println("Cannot use");
    }

我没有把所有的代码都放上来,但是如果我解释不清楚,我可以。

【问题讨论】:

  • 每个项目都实现了一个接口项目,它具有“useItem”声明。所有的项目都应该实现这个方法,并且在控制器中你只知道你在一个对象实例上调用 useItem 函数。它将是在他的实现中具有逻辑的项目。
  • 这意味着我将为每种类型的项目实现一个新类。会不会是多余的?
  • 您希望控制器中的每种类型的项目都有一个开关?

标签: java oop design-patterns adventure


【解决方案1】:

这是接口、继承和多态发挥作用的经典案例。每当您使用switchif 序列时,您都应该考虑多态性。

在这种情况下,为可用项定义一个接口或抽象类。

public interface Useable {
   public void useItem(Person personUsing);
}

现在每个item都实现了useable,你可以只检查一个item是否可用,是否显示使用它的选项并在使用时调用该方法。

【讨论】:

  • 如果我这样做会不会有太多单独的项目类别?
  • 一点也不,单独的类并不是一件坏事(除非它变得疯狂),你会发现这使得代码更清晰、更易于理解和更高效。
【解决方案2】:

作为 SOA(面向服务的架构)开发人员,我不会在我的项目中添加逻辑,因为在这种情况下很难分解和合理化我的代码。此外,如果您想要可扩展的代码,请记住 composition is far better than inheritance

public interface ItemInterface { 
    public String getName();
    public String[] getCharacteristics(); 
}

我会定义一些处理逻辑的物品效果:

public interface ItemEffectInterface {
    public String getName();
    public void affectCharacter(ItemInterface item, CharacterInterface character, parameters);
    public void affectInventory(ItemInterface item, InventoryInterface inventory, parameters);
    public void affectGame(ItemInterface item, GameInterface game, parameters); 
}

我为我的所有对象使用接口以在我的类之间创建低耦合(这提供了更具可扩展性、可维护性和可测试性的代码)。

如果您想在扩展器项效果中为所有方法定义默认行为“什么都不做”,并且只为每个效果定义活动方法,您可以定义一个抽象类 AbstractItemEffect

然后,如果您想要一个动态可配置的游戏,您可以在文件/数据库中定义项目和效果的交互。这是一个 JSON 示例:

[
    {
        "item": "health potion",
        "effect": "heal",
        "parameters": {
            "hp": 100
        }
    },
    {
        "item": "mana potion",
        "effect": "regen",
        "parameters": {
            "mp": 150
        }
    },
    {
        "item": "mana potion",
        "effect": "drunk",
        "parameters": {
            "duration": 1000
        }
    },
    ...
[

然后使用服务类将效果映射到使用时的物品:

public class ItemUser {
    private Map itemEffects = new HashMap();

    // Call it at service initialization after interpreting the configuration
    // (configuration is optional, you can call it directly of course).
    public void addItemEffect(ItemInterface item, ItemEffectInterface itemEffect, parameters) {
        Map effect = new HashMap();
        effect.push("effect", itemEffect);
        effect.pust("parameters", parameters);

        this.itemEffects.put(item.getName(), effect);
    }

    // Call it when you want to use an item.
    public void useItem(ItemInterface item, Character character, GameInterface game, InventoryInterface inventory) {
        Map itemEffects = this.itemEffect[item.getName()];

        // Process all the effects attached to your item 
        // on game, character, inventory, ...
    }
}

使用此架构,您可以将效果附加到许多项目,并将项目附加到许多效果。这应该可以防止您重复代码。

同时,每个物品和物品效果都会处理自己的复杂性,不会让整个系统变得更复杂。这与您在2. 中描述的模式“switch case”不同。想象一下,如果您有 100 个效果和 200 个项目,那么您的班级......

抱歉,我的 JAVA 代码错误/不完整!

【讨论】:

  • 您好,很抱歉回答晚了,非常感谢您的完美回答,我想我也可以将它用于任何其他游戏元素(武器、盔甲等)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-10
  • 1970-01-01
  • 2017-12-03
  • 1970-01-01
  • 2013-11-26
  • 1970-01-01
相关资源
最近更新 更多