潜在无用对象

3
在编写“通用RPG编号3,742”时,我为“物品”和“库存”实现了一个类。从概念上讲,“物品”是指一种特定的物品。我想要一种方法来“堆叠”物品,这样我在“库存”中每种“物品”只需要一个条目。
为此,我创建了一个“物品包装器”,它具有一个私有“物品”和“物品数量”。它还有一些处理获取所有这些“物品”的总重量等的方法。
随着我的扩展,问题就来了。我发现自己想要复制几乎每个“物品”方法到我的“物品包装器”类中。另一种选择是将“物品”设为“公共”,并在“库存”类中引用它,这同样不好。
这是“物品包装器”不应该存在的信号吗?这会在“库存”中创建重复的物品或使“物品”概念变成单数形式。我觉得可能有更好的解决方案,但我似乎找不到它。
编辑:增加了有关当前类结构的更多说明。
“玩家角色”有一个私有“库存”。
“库存”有一个私有[mumble]“向量”,其中包含“物品包装器”。
“物品包装器”有一个私有“物品”和私有“int”“how_many”。
请注意“有”。随着我对“库存”的扩展,我注意到我需要“物品名称”或其他特定于“物品”的东西。如果我不改变我的设计,要么将“Item”中的所有“Get”函数复制到“Item Wrapper”中,要么在“Item Wrapper”中使“Item”公开。

1
你考虑过使用 Item 的集合吗?一个 wrapper 通常包含单个实例,就像糖果一样。 - maasg
将项目方法暴露在包装器中对我来说没有意义。一组项目不是一个项目。 - Dave Newton
3个回答

5

你的ItemWrapper类型听起来可能是一个组合模式的例子,这是一种非常常见的设计模式。如果是这样,我不认为它是多余或无用的。


你分享的链接谈论的是树结构,这并不是我要找的。组合设计模式必须是一个吗? - RowlandB

4

我认为你把问题想得比实际要复杂。你可以通过在Item添加一个quantity字段并提供一个方法来计算quantityweight的总重量,从而简化问题。你的ItemWrapper没有添加任何额外的内容,只需添加一个字段和方法即可。


如果您想将一组项目视为单个项目,则“ItemWrapper”类型非常有用(请参见我的早期答案)。 - Greg Brown
@GregBrown 我想问题的另一部分是“单个项目的概念是否有用?它是否可以轻松地被“一个或多个项目”所取代?” - RowlandB
1
@RowlandB 我刚刚仔细看了一下你的原始问题。对我来说,拥有一个公共的 ItemWrapper 类型但是私有的 Item 类型似乎很奇怪。如果你真的只需要存储物品的类型和相关数量,那么也许你可以使用一个类型到数量的映射,其中映射键是物品类型。映射值将是该类型物品的数量。 - Greg Brown
@GregBrown 这是我的建议,但似乎提问者并不信服。 - kstandell

1
你所描述的让我想到了使用Map会很好。为什么不使用类似以下实现的Inventory呢?(保留html标签)
public class Inventory {

private static final int MAX_SIZE = 10;

private final Map<Type, List<Item>> inventoryItems = new HashMap<Type, List<Item>>();

// Keep track of the total number of items in the inventory
private int totalSize;

public void add(Item item) {

    // If the total size is greater than the max then don't allow the operation...
    if(totalSize == MAX_SIZE){      
        throw new IllegalStateException("Exceeded maximum size");
    }

    if (!inventoryItems.containsKey(item.getType())) {
        inventoryItems.put(item.getType(), new ArrayList<Item>());
    }

    inventoryItems.get(item.getType()).add(item);

    totalSize++;
}

public List<Item> getItems(Type type) {
    return inventoryItems.get(type);
}

public int getTotalWeight() {

    int total = 0;

    for (List<Item> items : inventoryItems.values()) {
        total += calculateTotalWeight(items);
    }

    return total;
}

public int getTotalWeightByType(Type type) {
    return calculateTotalWeight(inventoryItems.get(type));
}

private int calculateTotalWeight(List<Item> items) {
    int total = 0;

    for (Item item : items) {
        total += item.getWeight();
    }

    return total;
}

public void remove(Item item) {
    // Remove the item from inventoryItems and decrement the count
    totalSize--;
}

}

消除了您的ItemWrapper类的需要。

然后,您将拥有一个Character类,看起来可能是以下内容...

public class Character {

private final String name;

... // Any other fields

private final Inventory inventory;

public Character(String name) {
    this.name = name;
    this.inventory = new Inventory();
}

...

public void addToInventory(Item item) {
    inventory.add(item);
}

public List<Item> getItemsByType(Type type) {
    return inventory.getItems(type);
}

public void removeFromInventory(Item item) {
    inventory.remove(item);
}

...

}

注意: 您提到正在使用Vector,这会在每个操作上增加同步开销(可能是不必要的)。我认为您使用Map没有任何问题...


使用Map能给我什么?Item Wrapper的目的是提供简单的计数,但同时也节省空间(在概念上以及计算上)。这种解决方案不一定有助于计算-在现代计算中这不是一个问题吗? - RowlandB
1
@RowlandB 我觉得你把问题复杂化了。 - kstandell
我只是不熟悉Map,所以在接受任何东西之前,我正在努力理解它们。 - RowlandB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接