Solved Why are you discouraging using singleton pattern for getting the instance of the main class?

Discussion in 'Plugin Development' started by Deleted user, Aug 16, 2015.

Thread Status:
Not open for further replies.
  1. Offline

    Deleted user

    I have recently contributed this answer on this question at Stack Overflow.
    Then another user said:

    To compliment Francesco's answer, at the Bukkit forums we discourage using singleton pattern for the main class of your plugin because it leads to issues when reloading the plugin. We suggest using another class to hold necessary data such as a singleton, but not of the class that extends JavaPlugin. I personally use a Resources singleton class in all of my plugins for easy access, but I am able to reinstanciate the data in the Resource class on demand while doing so for the main class will run into major issues.​

    Why are you discouraging using singleton pattern for getting the instance of the main class?
    How should this be done instead?
     
  2. Offline

    Hawktasard

    @Joiner
    Code:java
    1. public class MainClass
    2. {
    3.  
    4. public static void main(String[] s)
    5. {
    6. new MainClass();
    7. }
    8.  
    9. public MainClass()
    10. {
    11. new AnotherClass(this);
    12. }
    13.  
    14. public void someMethod()
    15. {
    16. System.out.println("Hello.");
    17. }
    18.  
    19. }
    20.  
    21. public class AnotherClass
    22. {
    23.  
    24. private MainClass main;
    25.  
    26. public AnotherClass(MainClass main)
    27. {
    28. this.main = main;
    29. main.someMethod();
    30. }
    31.  
    32. }
     
    Shortninja66 and Synapz like this.
  3. Offline

    teej107

    @Joiner I prefer the pass-by-reference approach. Classes that can only access certain things make them easier to keep track of what they do and to manage. If a class requires an object in one of the parameters via constructor or method, then it's obvious that class relies on the Object being passed.
     
  4. Offline

    mythbusterma

    @Joiner @teej107

    This all being said, as far as the original intent of the singleton design is concerned, a Bukkit plugin actually fits quite well. I use it in most of my plugins, where passing the instance of the JavaPlugin class would become cumbersome (like in classes that hold data for players, for example). I still pass a reference to it when that is the best approach, however.
     
    teej107 and Konato_K like this.
  5. Offline

    Deleted user

    Thanks for answering my second question. Looking for an answer to the first one.
     
  6. Offline

    Konato_K

    @Joiner I've seen people (normally the ones who don't know Java and copy paste youtube tutorials) to have a "public static Main main" line normally in their plugins, they sometimes never initialize it and get random NPEs everywhere, then they come here saying their plugin doesn't work and they don't know why.

    I guess this is one of the reasons why it's discouraged, a singleton is sometimes considered an anti-pattern, but of course, if done properly there shouldn't be any issues about it (at least not something serious).
     
  7. My assumption is that many people simply forget to clean up the static reference, when onDisable is called. I am not entirely sure if there is a prectically relevant case, other than using the reload command/functionality or disabling and re-enabling a plugin on the fly. In general the static reference might stay, preventing unloading that version of the class. Of course a simple set-to-null call in onDisable would remove the issue. From there on, you could also wrap the not-as-essential parts by try-finally and ensure the references get removed even in case of failures (sanity depends on what your plugin is actually doing there, of course).

    Static plugin getters might also encourage problematic design decisions, e.g. making the plugin itself a monolithic do-it-all thing and passing it around everywhere as API, instead of using interfaces for (much) separated interactions, which certainly should be a concern for more complex plugins.

    In general static dependency mechanisms are not necessarily that bad, provided they're getting cleaned up properly. In the context of Bukkit i'd rather have one static-API-provider class. Alternatives would be to pass plugin references everywhere, or to make a static utility method wrapping Bukkit.getPluginManager().getPlugin(...) including casting and null checks, or using the Bukkit service API. In case of ever-shifting designs and uncertain future-additions, i'd rather go with context-dependent interfaces, passing those to constructors or use setters and/or provide them with a static provider class (not much different to having a static method in the plugin class), all provided your plugin reaches "some level" of complexity.
     
    Synapz and (deleted member) like this.
  8. Offline

    Konato_K

    Mentioning the getPlugin method of plugin manager, JavaPlugin has a static method with the same name which takes a String and well... returns JavaPlugin, so we don't really need to have a singleton-like class to get the instance of our plugin from anywhere.
     
    Synapz and asofold like this.
  9. Offline

    Deleted user

    Last edited by a moderator: Aug 23, 2015
    Konato_K likes this.
  10. Yes, that's a good reason not to implement another one (the method had been added after me setting up most of my plugins). This way you have YourPluginClass.getPlugin(YourPluginClass) for the typical case.

    That method contains a couple of extra checks (https://github.com/Bukkit/Bukkit/bl...a/org/bukkit/plugin/java/JavaPlugin.java#L486), but for performance critical (slightly odd) plugin getting, storing an API instance should be best, despite modern JIT possibly erasing the difference here.

    Concerns about using the implementation of JavaPlugin instead of interfaces for API will stay with this method, of course.
     
Thread Status:
Not open for further replies.

Share This Page