singleton and inheritance in Java

前端 未结 6 603
鱼传尺愫
鱼传尺愫 2021-01-17 16:30

I have a base class that captures some functionality common to two classes. In other words, I can create one base class and make these two classes subclasses of that base cl

相关标签:
6条回答
  • 2021-01-17 16:47

    I'm not an expert in Java, so I don't know if this is technically legal Java code (perhaps another poster can comment):

    Make the base classes inherit from a generic class Singleton.

    Example:

    class Singleton<T> {
    
        protected Singleton(); //constructor
    
        private static T _instance;
    
    }
    
    class DerivedOne extends Singleton<DerivedOne>{
    
        protected DerivedOne(){} //constructor
    }
    
    class DerivedTwo extends Singleton<DerivedTwo>{
    
        protected DerivedTwo(){} //constructor
    }
    
    0 讨论(0)
  • 2021-01-17 16:53

    Inheritance is not the only way to re-use common functionality. Containment may be preferable in the general case. Consider the following solution in which class A and B are the singletons, and the common functionality is in class AB, but instead of extending AB, both A and B use an instance of AB which is a singleton itself.

    class AB { //common functionality of A and B
       //singleton pattern here
       //common data and functionality here
    }
    class A {
       private AB ab = AB.getInstance();
       //singleton pattern here
       //unique functionality and data of A
    
       //to use any of the functionality in AB delegate to member ab
    }
    

    class B is similar to A.

    in this solution there is a single instance of every data and functionality of both A and B (and AB)

    Note that if clients of A and B need to access the common public methods in AB, then AB, A and B should implement an interface of those public methods, and A and B implementation should delegate the call to ab.


    The solution proposed by Ernest below, may be a shortcut in some situations, but in general is a wrong solution.

    To explain why Ernest's solution may be wrong, let's describe that solution in a different way. Suppose i have a singleton class A and i discover that i need to write another singleton class B, but i need some of the functionality of A in B. So i factor out the common data and functionality of A into an abstract class AB and make both A and B extend AB. The reason why it's wrong, in general, is because this solution takes a subset of the data and functionality which is supposed to exist only once, and places it in a sub-class (AB), effectively and potentially duplicating it in every sub-class that will be created. Now, after getting an instance of A and an instance of B, you have two instances of the subset data and functionality in AB.

    If for example, the common functionality placed in the base class writes some initial data to the file named "myData", then both of your singletons will execute this code even though it was only meant to be executed once, and when the later executes it it will wipe out the file created by the former.

    Therefore, in general, the solution described here does not use inheritance, and ensures that a singleton encapsulates the common functionality as well as the singleton classes that use it.

    0 讨论(0)
  • 2021-01-17 16:54

    I had a similar requirement: I had multiple cache maps with repeating methods and members, so I've created an abstract class like:

    public abstract class AbstractCache<T> {
    
        protected final Map<String, T> cache;
    
        protected AbstractCache() {
            this.cache = getDefaultExpiringMap(TimeUnit.HOURS.toMillis(4));
        }
    
        public Map<String, T> getCache() {
            return cache;
        }
    
        public T getAll(String id) {
            return cache.get(id);
        }
    }
    

    Then I've extended this class and created a singleton instance:

    public final class FooCache extends AbstractCache<Set<Integer>> {
    
        public static final FooCache INSTANCE = new FooCache();
    
        private FooCache() {
            super();
        }
    
        public void add(String fooId, Integer value) {
            cache.computeIfAbsent(fooId, k -> new HashSet<>()).add(value);
        }
    }
    

    And the usage:

    public static void main(String[] args) {
        FooCache.INSTANCE.add("a", 1);
        System.out.println(FooCache.INSTANCE.getAll("a"));
    }
    
    0 讨论(0)
  • 2021-01-17 16:55

    I don't know if you need an example but I gave it a try. Without knowing any of your details this example is very vague. I am also here to learn so let us know what you end up implementing.

    The Base class:

      public abstract class BaseClass {
    
            public void someMethod() {
                System.out.println("base class hello: " + this);
            }
    
            public abstract void someOtherMethod(String value);
        }
    

    One of the subclasses:

    public class SubClassOne extends BaseClass {
    
        private static SubClassOne instance;
    
        private SubClassOne() {}
    
        public static SubClassOne getInstance() {
            if (instance == null) {
                instance = new SubClassOne();
            }
            return instance;
        }
    
        public void someOtherMethod(String value) {
            someMethod();
            System.out.println("sub class hello: " + value + " " + this);
        }
    
        public static void main(String[] args) {
            SubClassOne one = SubClassOne.getInstance();
            SubClassOne two = SubClassOne.getInstance();
            SubClassOne three = SubClassOne.getInstance();
            SubClassOne four = SubClassOne.getInstance();
            one.someOtherMethod("one");
            two.someOtherMethod("two");
            three.someOtherMethod("three");
            four.someOtherMethod("four");
        }
    }
    
    0 讨论(0)
  • 2021-01-17 17:01

    You can make each class separately a singleton, and make the base class abstract. Not sure what's the debate -- just that singletons, in general, aren't a great idea?

    0 讨论(0)
  • 2021-01-17 17:08

    Use the Abstract factory pattern. Have a separate class with methods to retrieve the singletons, and let it hold the references to the singletons in instance variables or in a map.

    You may not want the increased complexity, but frameworks like Spring were created to solve these kind of issues (among others).

    It seems that Pico Container is alive and well, and it may be the simplest while still solid solution. Look at the inversion of control topics, and let the framework inject the singletons where you need them.

    In short, don't try to make the singletons manage access to themselves. Delegate that on something else.

    There's nothing inherently wrong in having singleton classes with complex inheritance. In fact, class hierarchies with private constructors (no instances) are very useful in many situations. You just have to decide how you want to manage the two important aspects of singletons: creation, and access.

    0 讨论(0)
提交回复
热议问题