Multiple Classes for Commands

Discussion in 'Spigot Plugin Development' started by Nathanacus, Jun 5, 2017.

  1. As I've been getting my feet wet with plugin development, I've so far been putting all methods for my commands in the same class file as onCommand(). Now that I have some working plugins, I'd like to clean up my files and implement a better organizational structure.

    So, my question is regarding multiple classes -- if I have a separate class for each sub-command, is it more efficient to instantiate a new instance of the class each time the command is given, or to instantiate one instance at the very beginning, and then call upon it as needed? For example, take this sub-command:
    Code (Text):
    // bank help
    else if (args.length == 1 && args[0].equalsIgnoreCase("help")) {
        cmdHelp(player);
    }
    If I wanted to make a separate class out of cmdHelp (rather than have it be a method in the same class), would I be better off with:
    Code (Text):
    else if (args.length == 1 && args[0].equalsIgnoreCase("help")) {
        CmdHelp help = new CmdHelp(player);
    }
    every time the command is entered, or should I create a "CmdHelp" at the very beginning, with something like this:
    Code (Text):
    CmdHelp help = new CmdHelp();

    . . .

    else if (args.length == 1 && args[0].equalsIgnoreCase("help")) {
        help.cmdMethod(player);
    }
    My primary concern is efficiency, so if they're both equally efficient, then I guess that's that.
    Thanks in advance! I appreciate it!
     
  2. It'd be better to only create an instance of the class one time, but personally I see no point in separating sub commands into different classes, I just have one class for each command.
     
    • Agree Agree x 1
    • Useful Useful x 1
  3. Thank you for the fast reply! My concern with leaving everything in one class is that I often have a dozen or more sub-commands, many of which rely on two or three separate methods, so the class file gets a little (lot) cluttered. I agree it doesn't really matter other than from a file organization standpoint, so I may rethink my approach.

    Anyway, thank you!
     
  4. Mas

    Mas

    A good way is to use abstraction; create an abstract command class which stores all information about a command (permissions, aliases, player only/op status, etc) as well as an abstract execution method. Then, when a player executes a command, loop through your custom commands, see if one of the aliases matches, and call the execute method.
    This completely eliminated the need to add a new statement every time you add a command.

    You can then apply the same logic to sub-commands.
     
    • Agree Agree x 1
  5. I am not a big fan of that, Sometimes you want to make one sub command that can be used by player only but on some occasions for everyone. Same with permissions...

    If the command will be run a lot of times, i would create 1 instance. If the plugin is used rarely i would suggest you create a new instance every time. It is just the trick to balance creating new instances and garbage collection against having to use more ram when not used.
     
    • Useful Useful x 1
  6. So, that was my main worry with creating new instances -- I'm not super clear on how garbage collection works, so I'm reluctant to either create new instances unnecessarily, or to have unused instances sitting around waiting to be used.

    This is for a small server, so just that alone means the commands won't be run very frequently -- so, assuming I were to create a new instance each time, how long do instances remain in memory before garbage collection takes them? My understanding is that garbage collection won't take anything until there's no chance of it being used again, but I'm not sure of how that works in practice.
     
  7. Mas

    Mas

    You're correct in that the garbage collector won't collect any objects until they are not being used at all.
    I really don't think there's any advantage to creating multiple instances of a command class - It's going to do pretty much the same thing each time, obviously different for arguments etc.
     
  8. Because when you have more than 2 commands it becomes unmaintainable

    When the object isn't referenced anymore it will be garbage collected. The speed at which it is cleaned up depends on the collector but in general you'll see them gone in terms of seconds.

    Having an instance of an object which handles commands for you isn't a waste of memory, you create a single object (with probably 0-few fields), so the memory footprint of a command object is on the scale of bytes. Throwing out new objects every time the command is used just fills up heap space and will cause a gc quicker (but of course that's relative to how much command input you have).

    You'll see objects cached like that in a Map<K, ?> a lot.
     
  9. I always separate each command into its own class, but not subcommands. No point in that from my point of view.
     
  10. Mas

    Mas

    Try making a command with 5+ different arguments, and then different options for each of those arguments based on the following arguments. :p Becomes a right mess if done in a single class.
     
    • Optimistic Optimistic x 1
  11. That is why i use my custom annotation based command system, Every class is 1 command, and in that class you can have unlimeted methods. Every method that has my CommandHandler annotation and a CommandArgument as argument will become a executer. Then you can set the executor (player, not player, console, not console, other or not other) and the "subcommand" in the annotation to the subcommand using placeholders like %player and %integer and that shit. Then, when the object returned is null or void, there will be nothing done after, when it is a CommandOutecome, the messages in that object will be send to the player, when it is a JsonCommandOutcome, the json text in that class will be send and when it is a object, the return value of String.valueOf(Object) will be send. This works very fine and keaps your code clean and uses only 1 class per command.