3

I'm trying to implement something to this effect:

  1. Base class A has a method getFileName()
  2. Two derived classes B and C have overridden implementations of that method, returning file names specific to B and C.
  3. Class A needs to use the services of a singleton class S
    • The reason I want it to be a singleton is because (a) I want a guarantee that it will only be constructed once and (b) I want eager initialization of that class, which happens at app startup, and not at first use.
  4. Class S needs to do its work work based on the file name (E.g., read in the contents of that file) - which depends on which of A's subclasses is used.

This seems to present an unavoidable conundrum, because:

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

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

  • ... and making getFileName() static will make sure that it cannot use inheritance overrides!

How can I implement this design? (I'm open to changing the design if a better pattern is available)

Community
  • 1
  • 1
DVK
  • 126,886
  • 32
  • 213
  • 327
  • will this be used in a web app server? if so which one? –  May 11 '15 at 20:57
  • @JarrodRoberson - a set of Swing apps (each app implemented via one of the derived classes, e.g. B-App and C-App). Why does it matter, if I may ask? – DVK May 11 '15 at 20:58
  • with a single classloader or multiple classloaders? –  May 11 '15 at 20:59
  • @JarrodRoberson - single. – DVK May 11 '15 at 21:00
  • 1
    it's apparently a design flaw, but we don't know enough of your problems:) – ZhongYu May 11 '15 at 21:00
  • making `getFileName()` **final** will do the same thing and it will testable as well! –  May 12 '15 at 01:39
  • also `Singleton` is a behavior pattern not a construction pattern, how you construct it is irrelevant that it is a `Singleton`. –  May 12 '15 at 01:44

3 Answers3

3

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

That means the Singleton is not really your problem, it is the acquisition of the correct class based on the type asking!

Your design is too tightly coupled the way you are trying to do it. You need to completely decouple the Service from the Consumers of the service, Singleton is not important in this exercise.

What you need is some form of dependency injection.

This is exactly the type of problem that Guice was created to solve by being able to provide what classes get injected based on another classes type in a binding. That said ...

Most people do not realize that Java has always supported DI via the Constructor. Guice makes this less hard coded, but it is still a dependency that is injected to an instance.

Guice would make this trivial by injecting the correct service based on the class type. But it can be done without any DI framework/library. If using Guice is considered to heavy handed for your case then it can still be done easily.

Below is one way to do it without a 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 singleton anti-patterns you mention are just that:

The Singleton pattern should by hidden behind a Factory pattern. Your consumers of what needs to have 1 and only 1 should not care if there is 1 and only 1. They should only care that that object conforms to some contract of some interface.

My implementation is a naive Factory to create in static block. Most are create on first use which is not any better.

Using Enum to create Singleton objects is a misuse of the semantics of Enum and an anti-pattern and impossible to properly unit test.

Same with the all static utility class approach, impossible to unit test or replace with a different implementation. A combination of the two is a complete abomination that is impossible to unit test and a complete nightmare to maintain!

How you determine which subclass of A the Singleton works on is easy:

That is what overloading is for as shown in the code above.

Anything else is not doing it right. instanceof fail, reflection bigger fail.

Selecting logic based on Type can be done with overloading methods, or generics or with the appropriate design pattern.

Strategy Pattern would account for that easily and make N number of subclasses manageable and extensible at runtime.

  • It seems that both Strategy and Factory pattern require me to have a single class that knows about existence of both B and C at the same time. This is 100% contrary to my design needs, where B and C should be independent (and someone should be able to add D at will, merely by sub-classing) – DVK May 12 '15 at 01:32
  • then you will have to resort to `Guice` or some other `DI` library, and guess what you will **still** need a single class that *knows* about the mapping of dependencies, the different with what I showed you and your approach is this is indeed only **in one place** that is easy to understand why it is there and what it does. This is much like the `Controller` in `MVC` having to *know* about the `M` and `V` there is no way getting around it. Reflection is not the answer, not for something like this, at least not manual reflection. `Guice` handles the mapping for you, but again in a `module`. –  May 12 '15 at 01:36
  • your *design needs* are contradictory at least using only what the `JDK` provides. I would recommend a long study session on `Guice`. I was working up a *strawman* Guice example earlier. When I get it done I will post it up as well. –  May 12 '15 at 01:37
0

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

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

If A uses S, then A should be abstract with respect to getFileName() forcing an implementation to be constructed, and it should internally call it's yet-to-be-defined getFileName() passing that as an argument to S.

Singletons are the glue between Object-Oriented solutions and non-Object-Oriented solutions, so you avoid the conundrum by

  1. Having your objects passed to the non-object oriented singleton "utility routine"

  2. Having the resolved parameters passed to the non-object oriented singleton "utility routine"

Example code for the first technique

// 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) {
    ...
  }
}
Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • A uses S. However, S needs to know which of the 2 flavors of A are using it to load correct configuration file (the ONLY information it uses from A is essentially "which of your 2 subclasses are being initialized in this app") – DVK May 11 '15 at 21:16
  • Then you have class-specific logic in S that undermines the Object contract. Classes are conceptually "data and behavior together" and you have data in the subclasses, but behavior in S. I'd recommend moving the behavior in the subclasses perhaps having the subclasses call the appropriate "smaller sized" calls in S (if it can't be moved). Nobody said you needed only one S call. If you really get down to it, you could have a call in S for each subclass, with them all entering the utility at different methods. – Edwin Buck May 11 '15 at 21:46
-1

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