1.3 Item 类和 ItemStack 类
前面两节叙述了加入普通自定义物品(item
)的大致流程。现在深入一下更抽象的层面,考虑这些物品背后的类,以便我们进一步对它们进行自定义。
首先,很方便理解的是 Item
类,就是规定每种物品属性的类。细心的同学可能会提问,我们之前创建的 ObsidianIngot
这个类在游戏的框中显示的数量呢?一组应该是多少个呢?Item
类都没有定义。
这是因为,设计者考虑到 item
的有些信息不会因为数量、耐久等参数的改变而改变,例如:
- 使用/放置(左键/右键)的行为;
- 在客户端上显示的名称及 Tooltip;
- 合成配方;
- et cetera;
这些抽象的属性都在 Item
类中得到定义;而数量、是否有/有多少耐久等信息,就单独提出去打包为一个类,其名曰 ItemStack
。游戏中,玩家的物品栏、背包、手持物品等,都是 ItemStack
的实例。
所以,可以将 ItemStack
和 Item
的关系看作类的聚集,在对 ItemStack
可以调用 getItem()
实例方法来获得其中含有的 Item
对象。
享元
另外有个极其重要的概念——“享元(Flyweight Pattern)”,即一种特定物品只对应一个实例,而 Item
就是一个享元。这意味着,以 Apple
类为例,你在游戏里见到所有苹果都是 Apple
类的唯一实例。正因如此,我们在编写 mod 中,可以直接用 ==
(即 <ItemStack_obj>.getItem() == <Item_obj>
)来判断 Item
种类,不用担心 ==
比较的是地址。
Item.AIR
还有一件事,由于 ItemStack
是 non-null
的属性,永远是非空引用,所以 MC 中 “空的” 栏的 ItemStack
所含的 Item
对象是个特殊对象:Items.AIR
。判断 ItemStack
对应的栏目物品是否为空时,应该使用专用的实例函数 isEmpty()
,不能直接判断是否为 null
。