How should I implement a singleton class if I need to use method overloading in its construction?

I am trying to implement something with this:

  • Base class A has a method getFileName()

  • The two derived classes B and C have overridden implementations of this method, returning file names specific to B and C.
  • Class A should use the services of class S singleton
    • The reason why I want it to be a singleton is because (a) I want to guarantee that it will only be created once and (b) I want to want to initialize this class, which happens when the application starts, and do not use first.
  • Class S must do its job based on the filename (for example, read the contents of that file) - depends on which subclass of A is used.

This seems like an inevitable mystery because:

  • most Singleton implementations are static-based (pure static class or ENUM with static parameter passing )

  • static classes / methods / blocks cannot call non-static methods ...

  • ... and making getFileName()

    static will ensure that it can't use inheritance overrides!

How can I implement this project? (I am open to redesign if a better template is available)

+3


source to share


3 answers


... one needs to use singleton services ... which depends on which of the subclasses of A is used:

This means it Singleton

is not really your problem, it is acquiring the correct class based on the request type!

Your design is too tightly coupled the way you are trying to do it. You need to completely separate Service

from the Consumers

service, it Singleton

doesn't matter in this exercise.

You need dependency injection.

This is exactly the type of problem that was posed for Guice

as it could ensure that the classes that were injected were injected based on a different type of class in the binding. Nevertheless...

Most people don't understand what Java has always supported DI

through Constructor

. Guice

makes it less hardcoded, but it's still a dependency that is injected into the instance.

Guice

will make it trivial by introducing the correct service based on the class type. But it can be done without the DI

framework / library framework. If the use Guice

is considered heavy for your case, then it can still be done easily.

Below is one way to do it without framework / library:

public class Solution
{
    static class Singleton
    {
        public static final Singleton INSTANCE;
        static { INSTANCE = new Singleton(); }

        private Singleton() { /* this is important */ }
        public void doWhatever(@Nonnull final B b) { /* whatever */ }
        public void doWhatever(@Nonnull final C c) { /* whatever */ }
    }

    static abstract class A
    {
        private final Singleton s;

        public A(final Singleton s) { this.s = s; }

        public abstract String getFilename();
    }

    static class B extends A
    {
        public B(final Singleton s) { super(s); }

        @Override
        public String getFilename() { /* code goes here */ }
    }

    static class C extends A
    {
        public C(final Singleton s) { super(s); }

        @Override
        public String getFilename() { /* code goes here */ }
    }
}

      

The single anti-patterns you mentioned are only:



The template Singleton

should hide behind the template Factory

. Your consumers of what should have 1 and only 1 shouldn't worry if there is 1 and only 1. They only need to take care that this object conforms to some contract of some interface.

My implementation is naive Factory

to be created in a static block. Most of them are created on first use, which is no better.

Using Enum

to create objects Singleton

is a misuse of semantics Enum

and anti-pattern and not possible for a proper unit test.

Same with all static utility class approaches, not possible to unit test or replace with another implementation. The combination of the two is a complete abomination that cannot be unit tested and a complete nightmare to maintain!

How do you determine which subclass A

Singleton works:

This is what overloading is, as shown in the above code.

Anything else doesn't do it right. instanceof

fail, reflection

larger failure.

The selection of logic based on Type

can be done using overloading or generics methods, or with an appropriate design pattern.

Strategy

The template will easily accommodate this and make the N

number of subclasses manageable and extensible at runtime.

+2


source


I think you need to decide if SA uses or uses S.

If S uses A, then A could be a base class or interface, and S will have a method that accepts instances of A that are overridden with the correct implementation getfileName()

.

If A uses S, then A must be abstract with respect to getfileName()

causing the implementation to be constructed, and it must internally call it undefined getfileName()

, passing it as an argument to S.

Singletons are the glue between object-oriented solutions and object-oriented solutions, so you avoid the puzzle with

  • Passing your objects into a non-object-oriented single-user "utility"

  • Having allowed parameters passed to the non-object-oriented single-user "utility"



Sample code for the first method

// this could be abstract class too, as long as getName() is abstract
public interface Nameable 
   public String getName();

}

public enum Utility {

   INSTANCE;

   public static deleteByName(Nameable nameable) {
      createBackup(nameable.getName());
      updateIntentLog(nameable.getName());
      removeFile(nameable.getName());
      updateAuditLog(nameable.getName());
   }

}

      

or

public abstract class Nameable {

  public abstract String getName();

  public void delete() {
     Utility.INSTANCE.deleteFile(getName());
  }

}

public enum Utility {

  INSTANCE;

  public void deleteFile(String name) {
    ...
  }
}

      

0


source


You can create singleton classes that you initialize manually, i.e. have a static instance variable, but also a static initialize () method. Initialization throws if you try to initialize twice. This allows you to choose at runtime which subclass to use, and also makes the order of initialization clear.

-1


source