4

I have a couple of simple classes that implement the Null Object pattern.

To illustrate the hierarchy, let's define a Config interface with two classes implementing it ConfigItem and MissingConfig, each defined in its own file.

// Config.java

public interface Config {

    Something process();
}

// ConfigItem .java

public class ConfigItem implements Config {

    // some fields

    @Override
    public Something process() {
       // some actual logic and return statement
    }
}

// MissingConfig.java

public enum MissingConfig implements Config {

   INSTANCE;

    @Override
    public Something process() {
        // do no harm
    }
}

In my case, the MissingConfig object is immutable and only a single instance is guaranteed to exist.

This works fine and allows me to avoid null-checks. However, the fact that this implementation of the Config interface exists can be missed by other developers working with the code.

I'm trying to find a way to make the reusable null-representation of the Config easy to find.

It occurred to me that I could expose it using the interface itself:

public interface Config {

    Something process();

    MISSING = MissingConfig.INSTANCE;
}

so that it would auto-complete for everyone trying to do something with Config

This, however, in a way, introduces a constant in the interface, which is advised against in Joshua Bloch's Effective Java (Chapter 4, item 19)

Another way to structure the code that occurred to me is to define the enum inside the interface.

public interface Config {

    Something process();


    public enum Missing implements Config {

        INSTANCE;

        @Override
        public Something process() {
            // do no harm
        }
    }
}

This looks almost as readable when consumed

Config.Missing.INSTANCE

but not as nice as the previous version... and technically, this is still a constant defined inside an interface. Just a bit more convoluted.

Is there any way I can make the consumption of the null-object blatantly obvious without violating the good practices of interface design... or am I trying to have my cake and eat it too?

I'm beginning to think my original implementation (with the enum defined in its own file) is the most elegant one and that the discoverability should be achieved by an explicit mention of it in the Javadoc. As much as I'd love to, I can't protect myself against people who don't read javadocs.

I have also thought about switching from an interface to an abstract class but that limits reuse in ways I cannot accept due to single inheritance (some existing code that has to do with the Config)

Hope this isn't too open-ended for Programmers

1
  • 1
    I think you misunderstood what Joshua meant. IMHO what he said was that putting your constants in an interface and nothing else, while expecting the interface to not be implemented is bad practice. I.e. having some methods and a constant in an interface is fine, having some constants and no methods (abstract or default) is not fine.
    – Ordous
    May 17, 2016 at 16:21

1 Answer 1

2

There is a sentence in the chapter you referenced (Joshua Bloch's Effective Java (Chapter 4, item 19)):

If the constants are strongly tied to an existing class or interface, you should add them to the class or interface.

and you could rewrite your examples to:

public interface Config {

  Config EMPTY = new Config() {
    @Override
    public void doSomething() {
      // empty for missing config
    }
  };

  void doSomething();
}

but some JAVADOC could be helpful for your colleagues.

1
  • That's my original implementation that I changed to the enum-based one (because it guarantees no superfluous objects are created) ;) Thaks for the quote. I lent someone my copy of the book and couldn't have a look myself. May 17, 2016 at 17:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.