9-2 使用 Kotlin 包
真假主程序
你一定已经对 plugin.yml 中的这个键非常熟悉了:
main: Main
它告诉 Bukkit,『插件的 onEnable 在 Main 这个类中!』,这样 Bukkit 就可以正确地找到并启用我们的插件。
大家有没有想过一个问题,我们这么多插件的主类都叫做 Main,如果把它们放在一起,Bukkit 还怎么区分哪个类是哪个呢?现代插件社区有这么多插件,如果个个都叫 Main,那可不就乱套了嘛!
如果你真的到服务器上去做这样的测试,你会发现尽管插件的主类都叫做 Main,但它们还是可以正常加载的,这是因为 Paper 比较聪明,在加载插件时会做一些特殊的处理,其中就包括把 Main 改成其它不会冲突的名字,例如 llo.cia.Main 之类。
但是,Paper 的这种行为不是所有服务端都支持,而且也并不稳定(有些类依赖于它们的名字才能正常工作),此外还会降低插件的加载速度。如果插件出了什么问题想要调试,也会更加麻烦。
除了要让 Bukkit 能区分『这个 Main 到底是谁的』,我们还面临着一个更大的问题:随着代码的增加,管理代码会变得非常困难。虽然我们已经知道如何把代码拆分到多个文件中,但大多数插件项目的代码都增加得非常快,以至于这些文件本身很快也就会乱成一团。
要解决这两个问题,我们就需要使用包(Package)。
创建和使用程序包
早在第一个项目里我们就介绍过包了,如果你已经忘记了相关的概念,这里再简要提及一下:包就是将一系列类、函数、变量等东西收集到一起的容器,和 Minecraft 中的箱子、硬盘上文件夹的功能差不多。
先前我们一直在使用包(例如通过 import 来使用 org.bukkit 包中的 Bukkit),现在就让我们来创建一个包吧!我们将继续使用 TOTP 项目的代码,不过你要是想在别的项目里尝试,也是完全 OK 的。
在 IDEA 中右键 src/main/kotlin 中的 kotlin 文件夹,并选择 New Package,在弹出的对话框中键入你想要的包名,例如 moe.skjsjhb.mc.plugins.totp 之类。
如果想破脑袋也拿不定该给包取什么名字,那么可以使用 你的昵称.mc.plugins.项目名称 来命名 —— 但是最好取一个更好的名称。
……还是拿不定注意?不如试试 ezhj.mc.plugins.qxd 怎么样?(名称为随机生成,点击可以刷新)
就规范而言,包名只能包含小写字母、点号 .、数字、下划线 _ 和美元符 $,数字不能在开头。不过,现行的 Java 标准几乎都建议只使用小写字母、数字和点号,尽量避免其它的符号。本书中的项目也会遵循这个规范。
在创建了包之后,就可以通过拖拽的方式,将先前创建的 Main.kt 和 TOTPListener.kt 放进新创建的包里,IDEA 会自动修改代码中相应的部分(例如 import 之类)。
移动了 Main.kt(同时也移动了 Main 类)之后,你可以再次打开 plugin.yml,IDEA 应当自动修改了其中 main 字段的值:
main: moe.skjsjhb.mc.plugins.totp.Main # 或者你选用的名称
这样 Bukkit 就仍然能在新创建的包中找到我们的插件主类。
在今后,如果还要创建新的文件,就要通过右键新创建的包,再点击 New Kotlin Class/File 来进行,也就是在包中创建文件(而不再是在根目录 src/main/kotlin 下了)。
将插件功能分类
虽然到目前为止我们都只有一个包,但在更大的插件项目中,通常会有很多很多的包,用来实现各种各样的功能,例如一个货币经济插件就可能有以下的包:
config:读取和验证配置command:解释和执行命令currency:管理各种不同的货币event:处理插件事件ui:用户交互
在 IDEA 中,通过右键一个包,可以『在其中』创建新的包,例如在 moe.skjsjhb.mc.plugins.totp 上右键并选择 New Package,并在弹出的窗口中增加 event,就可以建立名为 moe.skjsjhb.mc.plugins.totp.event 的包。
之所以这里要打引号,是因为我们前面已经提到过,包与包之间并没有包含关系。但从形式上来说,a.b.c 看上去好像是『在 a.b 中』的,因此我们有时也会说『在 a.b 中建立名为 c 的包』。当有人这样说的时候,不必去反驳他们,因为这是一种习惯上的说法,他们的意思其实是『在 a.b 后面加上 .c』,创建一个名为 a.b.c 的包。
在后面的更大型项目中,你会很快发现使用包来分门别类管理文件的重要性。