Design Patterns - What are they and why you should use them

Discussion in 'Resources' started by kumpelblase2, Dec 25, 2013.

Thread Status:
Not open for further replies.
  1. Hey everyone!

    Because of the fact that some people still say that having a static plugin instance is bad (yeah I know, "if you handle it correctly it's ok" bla, bla) and the structure of most plugins could be way better, I decided to make a post about design patterns.

    So first, what are design patterns? They are templates describing how the result of an implementation of an idea should look like. There are a ton of them, because there are a lot of ways to go about implementing an idea. These templates or patterns are used pretty much everywhere, are widely accepted and in the end will probably enhance your code a lot. But well, they are like a convention, you should, but you don't have to follow them.

    So why should you use them in the first place? The probably biggest reason is that they're proven to be good and work well. I'm not saying that your way is bad or won't work, but those patterns most of the time exist very long already and thus haven been used and improved a lot. Second, almost everyone can recognize them and understand the idea behind it quickly, which doesn't have to be the case with your implementation. Lastly, they are most of the times compromised to the very least giving you a good base to work with and extend upon. It also helps a lot when you don't even have an idea and just look around patterns which might do the job for you. In the end, it will not only improve your code, but makes it way easier for others to understand, so a win-win situation I'd say.


    Since there are so many of them (even whole 200 pages books or larger are filled with them) I'm just gonna give you some basic patterns that you can probably already relate to.

    First off, the singleton. This is probably one of the easiest ones and the one that you will most definitely be able to add in your plugin (but you might not need it). The idea is that there is only instance of a specific object at the time which you can access from everywhere. For example, here's a simple one:
    Code:
    public class Singleton
    {
        private static Singleton instance;
     
        private Singleton()
        {
        }
     
        public static Singleton getInstance()
        {
            if(instance == null)
                instance = new Singleton();
     
            return instance;
        }
    }
    This makes sure that only one instance will exist all the time and is accessible everywhere. When it comes to your plugin, it is given there will only be one instance of your main class at all time, thus effectively making it a singleton. You just have to keep track of the instance and you're done. The only thing that we can't do is make the constructor private to be completely sure that there will be only one instance, so we have to set the instance somewhere else, preferably in the onEnable. (You might want to also take a look at #12 when you're working in a multi-threaded environment.)

    Moving on, there's the state machine. It is used to do something depending on the state it is in, meaning it will do something else once it's state changes. This involves multiple objects: the machine and the separate states. These states can be completely independent or can depend on another, it's your call. So let us take a look at a state first:
    Code:
    public interface State
    {
        public void execute();
    }
    Pretty easy isn't it? You can, of cause, make it an abstract class and make it so it will need the machine in the constructor, or something else, but this is the basic one.
    Code:
    public class BeginState implements State
    {
        @Override
        public void execute()
        {
            System.out.println("test");
        }
    }
    This would be our first state, as easy as that. Now, here comes the machine itself.
    Code:
    public class Machine
    {
        private State m_currentState;
     
        public Machine()
        {
            this.m_currentState = new BeginState();
        }
     
        public void update()
        {
            this.m_currentState.execute();
        }
     
        public void changeState(State inNextState)
        {
            this.m_currentState = inNextState;
        }
    }
    It doesn't really look that complex either, does it? Sure, you might have a different name than update, but the principle is the same. So you will only need to call 'update' all the time and it the execution of the current state will follow. Once you set the state to something else, the execution will change.

    Next up is the adapter pattern. You are already using this one, if you're working with vault. An adapter provides the user with an unified set of functionality which, depending on the implementation of the functionality, will use the corresponding methods. In vaults example, it gives you access to a unified way to handle money transactions (chat, perms and whatnot) and depending on which plugin is installed it will use that plugin to execute it, despite the different implementations. So in the end, you just have to work with the adapter instead of the different implementations. To do that, you will have for example an interface describing the functionality and then have seperate classes which implement that interface but do different things, depending on the underling implementation of that feature. I'll give you a really small example here.
    Code:
    public interface Adapter
    {
        public void doSomethingWhatEveryoneDoes();
    }
    In this case, we only have one method, but they are different in out two implementations:
    Code:
    public class SomeClass
    {
        public void doSomething()
        {
            System.out.println("test");
        }
    }
     
     
    public class SomeClass2
    {
        public void doSomething2()
        {
            System.out.println("test");
        }
    }
    As you can see, they both do the same, but their methods are different (of cause, it's really on a simple and basic level, but you get the idea). Now, we just make two adapters, one for each different class, and use the respective methods.
    Code:
    public class SomeClassAdapter implements Adapter
    {
        private SomeClass clazz;
     
        public SomeClassAdapter()
        {
            this.clazz = new SomeClass();
        }
     
        @Override
        public void doSomethingWhatEveryoneDoes()
        {
            this.clazz.doSomething();
        }
    }
     
     
    public class SomeClass2Adapter implements Adapter
    {
        private SomeClass2 clazz;
     
        public SomeClass2Adapter()
        {
            this.clazz = new SomeClass2();
        }
     
        @Override
        public void doSomethingWhatEveryoneDoes()
        {
            clazz.doSomething2();
        }
    }
    So no matter what implementation there is, we will get what we want. In this case, we can just use 'adapter.doSomethingWhatEveryoneDoes()' and, depending on which adapter we have, will call the correct method. Like I said, this is on a really small level and it can get way bigger, like vault for example.

    The last pattern I want to show you today is the observer pattern. What it wants to accomplish is that you get notified or see when the thing, you're observing, changes. For example when you have a list of players and you need to do something once a player gets added or removed from the list, you could use this in order to have observers which get notified once the content of the list gets changed. This patterns involves two parties: the subject, which gets observed and the observers themselves. The observers are pretty easy:
    Code:
    public interface Observer
    {
        public void onNotify();
    }
    They only have one method which gets called once the subject they're observing got changed.
    Code:
    public class Subject
    {
        private List<Observer> m_registeredObservers = new ArrayList<Observer>();
     
        public void registerObserver(Observer inObserver)
        {
            this.m_registeredObservers.add(inObserver);
        }
     
        public void removeObserver(Observer inObserver)
        {
            this.m_registeredObservers.remove(inObserver);
        }
     
        public void doSomething()
        {
            for(Observer observer : this.m_registeredObservers)
            {
                observer.onNotify();
            }
        }
    }
    As you can see, you, as an observer, have to register yourself on the subject first and once something happens ('doSomething()') you will get notified by calling the 'onNotify' method. In this case I'm using a list, but a set, queue or whatever you find adequate is fine too - remember it just a pattern.

    I added some clarification for the singleton and provided some more examples for the usage of each pattern. You can find it below. (see #3)

    With that I end my post about design patterns. If you think that I missed an important one, feel free to leave a post here and share it with everyone. Like I mentioned, there are so many, you can also just look around the internet and you'll discover a lot more and probably some others which will help you in your situation. I hope this will help you improve your code!
    Have a nice day!

    ~kumpelblase2.


    P.S.: Sorry, seems like I can't write short posts ...
     
    flash110, Gnat008, Garris0n and 7 others like this.
  2. Offline

    Ultimate_n00b

    I gotta say, your resource posts are always quite interesting.
    Good job on this, short posts are overrated.
     
  3. Some clarifications and additions:

    Why can't we have a private constructor in our plugin and why do we need to set the instance in the onEnable?
    We can't make the constructor private because bukkit is the one responsible for creating our plugin and we thus need to provide it with a constructor to work with. Since bukkit creates our plugin instances, we can't create our own instance inside 'getInstance' like you'd normally do so we need to assign our instance at the first possible point after bukkit is done with our plugin which is the onEnable.


    Some more practical examples for each pattern:
    Singleton - Assume you have a datacenter for your plugin. It holds all the information you need at runtime, like which feature is enabled or it keeps track of statistics. Since it handles all the data, we only need one the whole time and it should be the only one. When we implement it as a singleton, we can guarantee that we will only have one single instance with the data and can access it everywhere.

    Statemachine - Lets pretend we have a card game were each turn consists of different phases. Each phase would then be a different state and depending on which phase it currently is, we can react to the player accordingly or do something which has to be done in this phase of the turn, like giving the player a new card. Normally, you'd probably just have a variable keeping track of the current phase and go through it with an if or a switch, but you'll end up with a huge chunck of code. Using the state machine, each phase has it's own state, it's own separate class to work in leading to a way cleaner code.

    Adapter - In this case, we could say that we have lot and lots of different entities but want to provide an unified way to make them all move somewhere (Assuming they are all able to move and there is a way to accomplish that). We just provide the user with a simple interface which gives him a single move method and we implement this interface for each entity or entity group. Depending on which entity we have, this adapter will do the correct method call for the corresponding entity we currently have. So no matter what entity we want to move, the user just needs that one single method and can rule them all.

    Observer - For this example, we have a button and we want to open a dialog when the button gets pressed. So we are the observer and want to be able to see when the state of the button changes. When we make the button a subject and register us on the button, when it gets clicked, loses focus etc. we will get called and see what happened. When it is now pressed we can then open our dialog. A lot of you might say that this looks similar to the event system of bukkit but there are some differences. In that case, you're not observing when it changes, but you are observing when it gets used (that's completely fine, since it's not defined that we can only observe when an object changes). The difference, however, is that an observer normally doesn't change what the subject does, because it only observes it and doesn't interfere with it, which you can obviously do in the event system.


    I hope these additions make parts clearer and help you find a suitable pattern.

    Ultimate_n00b Thanks! I don't like to post things that have been discussed several times already or are commonly known, because yeah, we don't need the same information three times with only little difference. Moreover, most people here aren't programmers who have a lot of experience and/or knowledge and thus don't know this kind of stuff just yet (or just don't feel obligated to share it).

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 5, 2016
    Gnat008 and bobacadodl like this.
  4. Offline

    Ultimate_n00b

    kumpelblase2 Haha, want me to delete my post? Seems like you meant for your second post to be right after your first.
     
  5. kumpelblase2 Nice post! I'm happy to finally see a thread that doesn't say "singletons are bad! Kill them with fire before they lay eggs", thank you for that :)
     
  6. Offline

    bobacadodl

    Wow, thanks for this! I'm self-taught in java, like most people here, and have never seen some of these designs.
     
    Garris0n likes this.
  7. You don't need to delete it, it's all fine.

    CaptainBern I ddin't understand why they said it in the first place. Like the only reason the have is "because if you don't handle it properly it will not allow the gc to collect it" or similar, but if you handle something else bad as well, it could cause all other sorts issues too.
     
  8. kumpelblase2 Indeed, I personally use singletons in almost every plugin I have.
     
  9. Offline

    Not2EXceL

    The simple reasoning imo of why they say its bad, is because of what the singleton was originally and mostly used for. However, in the case of plugins, if you pass the main plugin instance to every class it does the same thing accessing a singleton does, since there will never be another instance of the main plugin(unless you like breaking things).
     
  10. Offline

    Scullyking

    Anybody have a link to a tutorial that fully explains OOP concepts in relation to Bukkit? I don't understand Singletons because I don't really understand the whole instance concept.
     
  11. Offline

    xTrollxDudex

    kumpelblase2
    Watch out for thread safety when using singletons though, and avoid double-checked locking at all costs.

    The concept of double checked locking has been broken for a year or two that I know of, maybe even more. I belove the issue on this was brought up pre-JDK5, although I might be wrong. From the references that I use, it cites an article written in 1996, but largely ignored by the general amount of programmers. This issue is quite a minor one when only using a plugin, but that's just practice compared to what happens when multi-threading comes into place, when you need to use Threads for your heavy tasks.

    The singleton pattern is often used with utilities or accessor classes, therefore, it is not uncommon to see code running an asynchronous method from a singleton, at least that I know of. And anyways, people do stupid things as stupid times, as well as carelessly calling methods in a multi-threaded environment without knowing what they are doing. Using a singleton is an excellent way to prevent this as only one instance should be accessed.

    By controlling access in a safe manner, you can ultimately prevent several other errors and multi-threading issues when accessing methods from a utility. You can visit http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html to figure out some of the things that I am talking about, but I can summarize it right now:

    • Using the double check cannot prevent your instance from being null between thread to thread.
    • Synchronization will completely fail in the presence of "shared memory mutilprocessors" and "compile optimizers"
    • The write to your instance may be flipped on its head, the ordering of fields can be completely backwards
    • Solutions to this problem will always hit a wall when the rules of threading work the way you don't know they actually work in

    Therefore, you can conclue the use of singletons must be carefully monitered when doing big tasks, the instance may be null at any point in time at any thread which accesses the class. The implementation of a fix would go similarly like:
    PHP:
        private class WrappedSingleton {
            protected static 
    Singleton instance = new Singleton();
        }

        private static 
    volatile Singleton single;
        public static 
    Singleton getInstance() {
            if (
    single == null) {
                
    synchronized(Singleton.class) {
                    if (
    single == null)
                        
    single WrappedSingleton.instance;
                    }
                }
                return 
    single;
            }
        }
    This is a valid solution to the double-checked locking issue, it works in a multi-threaded environment without inconsistencies, however, it is a tradeoff of performance for thread safety.

    Then again, for a Bukkit plugin, something this safe is, in reality, something that isn't necessary. However, this is a heads-up for those who plan on implementing singletons within multiple threads, otherwise, ignore this post, it doesn't apply to you.
     
  12. xTrollxDudex Thanks, this is actually a valid point. I didn't think about thread safety because I only wanted to tell everybody the general idea behind design patterns.
     
Thread Status:
Not open for further replies.

Share This Page