Question

I am reading Effective Java. In a section that talks about using function objects as strategies, the below paragraph is present.

Because the strategy interface serves as a type for all of its concrete strategy instances, a concrete strategy class needn’t be made public to export a concrete strategy. Instead, a “host class” can export a public static field (or static factory method) whose type is the strategy interface, and the concrete strategy class can be a private nested class of the host

   // Exporting a concrete strategy
  class Host {
        private static class StrLenCmp
               implements Comparator<String>, Serializable {

        public int compare(String s1, String s2) {
            return s1.length() - s2.length();
        }
    }

    // Returned comparator is serializable
    public static final Comparator<String>
    STRING_LENGTH_COMPARATOR = new StrLenCmp();
    ... // Bulk of class omitted
  }        

My question is , is there any particular advantage of using the above way? What is the problem with exporting the strategy by making concrete strategy public?

Was it helpful?

Solution

Yes, there is. This way you are returning the interface and not the concrete class, so if you change the concrete implementation of Comparator interface you don't have to modify client classes too (I think this is the most important reason of using interfaces).

For example:

//inside aClass

Comparator c = Host.STRING_LENGTH_COMPARATOR; //Programming against interfaces is different from:
StrLenCmp  c = Host.STRING_LENGTH_COMPARATOR; //programming against concrete class

Suppose in the future you will change StrLenCmp with another implementation (let's call it NewStrLenCmp) than if you have programmed against interface Comparator you don't have to modify aClass.

Comparator c = Host.STRING_LENGTH_COMPARATOR; //still work because interface doesn't changed
NewStrLenCmp  c = Host.STRING_LENGTH_COMPARATOR; // problem: you need to modify the client class in order to use the new concrete type: bad idea

OTHER TIPS

It's the same problem as making anything public - encapsulation.

The narrowest possible scope for an object makes it much easier to reason about how that object is used, and can ease maintenance massively (you know a private object can only be used in the same source file you're looking at, but you can never truly know how many people are using a public object or in what ways).

Every Java program would work if you declared everything as public, sure. But it's a bit like Pandora's box - once you've opened up access to something, it's hard to take it back.

By not making the concrete strategy public, you prevent other classes/apps being able to use it for their own purposes, which means you don't have to worry about designing it as a fully-fledged, shiny, stable, public class with a well-defined interface. You can just write what works for you, right now, and know that you have the freedom to change it however you want later.

  • Public stuff is your API. If you ship your code and later need to change your strategy implementation, you have effectively broken your API for everyone you shipped code to.

  • So until otherwise required, everything should be in the narrowest scope possible.

  • We also put it into a static nested class because we aren't using this strategy elsewhere.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top