简体   繁体   中英

Java: [Global method access] enum with a single instance vs on-demand object construction vs static

I want to create a class with few methods which can be used anywhere inside a package. I opted to use enum with a single instance after reading that it automatically provides safe instantiation, serialization and protection from instantiating outside the enum. I believe it is the most easy and safe way of creating a singleton. But my superior came back saying that it's dirty programming. Is it really? Do anyone know the disadvantages of using an enum instead of object construction and passing around references using a class? When are enums initialized?

public enum Myenum {
    INSTANCE;

    public void init(...) {..initialize local variables...}

    public method1 (...) {...}
    public method2 (...) {...}
}

vs

public class Myclass {
    public Myclass(...) {...initialize local variables...}

    public method1 (...) {...}
    public method2 (...) {...}
}

vs

public class Myclass {
    public static void init(...) {...initialize local variables...}

    public static method1 (...) {...}
    public static method2 (...) {...}
}

In my view the disadvantage of using the second method is that an object reference of Myclass is needed everywhere I need to use methods and synchronization issues while object construction. I am not really using the serialization benefit of enum in my case.

Does enum implicitly provide the benefit of dependency injection? (ie Can access Myenum's method1, method2 everywhere inside the package without worrying about instance creation)

One other feature of enum I needed was methods inside an enum cannot be overriden outside of it.

Am I missing some obvious disadvantage here?

An enum gives a semantic signal to other programmers that it's a type with a series of possible values that you could check against, for example, in a switch statement. However, there are a number of compelling reasons why enums can be seen as a better implementation of a singleton pattern than most other patterns people typically use in Java.

If you're positive you want to use a singleton pattern, then using an enum is probably okay. However, there are patterns that tend to be more flexible, unit testable, SOLID, etc. What if one day you decide that you don't actually want this to be a singleton anymore? What if you want it to be refreshable when certain changes are made in the database? Using any singleton pattern is going to lock you into a singleton representation and make it harder to make changes like this in the future.

A Factory pattern would be more flexible than a singleton, but the best pattern of all, in my opinion, would be to use dependency injection. You can singleton-bind your type to avoid the costs of reinstantiating it, but the type itself (and its consumers) need not be tied to a specific lifetime or pattern.

I found an answer here to why creating a globally accessible pattern is bad instead of passing around references.

Excerpt:

  1. They are generally used as a global instance, why is that so bad? Because you hide the dependencies of your application in your code, instead of exposing them through the interfaces. Making something global to avoid passing it around is a code smell.

  2. They violate the single responsibility principle: by virtue of the fact that they control their own creation and lifecycle.

  3. They inherently cause code to be tightly coupled. This makes faking them out under test rather difficult in many cases.

  4. They carry state around for the lifetime of the application. Another hit to testing since you can end up with a situation where tests need to be ordered which is a big no no for unit tests. Why? Because each unit test should be independent from the other.

Check out Java Concurrency In Practice and it's static singleton pattern. It looks like this:

public class ResourceFactory {
    private static class ResourceHolder {
        public static Resource resource = new Resource();
    }

    public static Resource getResource() {
        return ResourceHolder.resource;
    }
}

It's safe due to how/when statics are initialized, probably for the same reasons the Enums singleton trick is safe.

In JCIP's example, it's returning a thing, but you can add all the static methods you want that use however many variables you want to initialize in the ResourceHolder. And there's no init() call required.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM