Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

static factory method in interface class java

I was reading Effective java text book. First item is about using static factory methods instead of public constructor. My doubt is that if i am specifying an Interface how can i specify a static factory method in the Interface ? Because java does not support static methods inside interface. The text book specifies about creating a non-instantiable class containing the public static factory methods. But how can those method access the private constructor of the implementation class?

The text book says if you are defining an Interface Type , create a non-instantiable class Types and include the static factory methods in that class. But how can a method defined in the Types class access the private constructor of a concrete implementation of Interface Type

EDIT:- Below sentence is quoted from the text book. Please explain me its meaning

"Interfaces can’t have static methods, so by convention, static factory methods for an interface named Type are put in a noninstantiable class (Item 4) named Types "

EDIT:- taken from Effective Java By Joshua Bloch: Item1 - Static Factory Method

     public interface Foo{ //interface without plural 's' (question 1)
     public void bar();
 }
 public abstract class Foos(){ // abstract factory with plural 's' (question 1)
    public static Foo createFoo(){
        return new MyFoo();
    }
    private class MyFoo implements Foo{ // a non visible implementation (question 2)
       public void bar(){}
    }
 }

My question is that how can the static method createFoo() calls the private constructor of MyFoo

like image 710
Manu Viswam Avatar asked Dec 13 '13 10:12

Manu Viswam


People also ask

Can factory methods be static?

The static factory methods are methods that return an instance of the native class. The static factory method has names that clarify the code, unlike the constructors. In the static factory method, we do not need to create a new object upon each invocation i.e object can be cached and reused if required.

Are factory classes static?

state data is not normally maintained by the factory class, so they're normally static.

What is the benefit to use static factory in place of constructor?

Static factory methods can encapsulate all the logic required for pre-constructing fully initialized instances, so they can be used for moving this additional logic out of constructors.

Which of the following options is a disadvantage of using a static factory method?

The main disadvantage of providing only static factory methods is that classes without public or protected constructors cannot be subclassed.


2 Answers

One way to think about this is with the package encapsulation in mind. Consider this Java 9+ code:

public interface Engine {

    void start();

    static Engine getEngine(String type) {
        switch (type) {
            case "combustion":
                return new CombustionEngine();
            case "electric":
                return new ElectricEngine();
            default:
                throw new IllegalArgumentException("Unknown engine type : " + type);
        }
    }
}

class CombustionEngine implements Engine {

    CombustionEngine() {
    }

    @Override
    public void start() {
        // injecting fuel and igniting it to create combustion...
    }
}

class ElectricEngine implements Engine {

    ElectricEngine() {
    }

    @Override
    public void start() {
        // electric current from battery flowing through coil in magnetic field...
    }
}

Note that constructors in implementations are package-private so the caller from a different package can't instantiate implementation directly and should use the factory method.

Having the factory method in the interface

  • has no need for a dedicated EngineFactory class (the traditional implementation of Factory method design pattern)
  • reminds to Program to interface, not implementation

If needed, there is also a way to create implementation instances as singletons, which improves memory footprint :

public interface Engine {

    enum EngineType {

        COMBUSTION,
        ELECTRIC;

        private static EnumMap<EngineType, Engine> MAP = new EnumMap<>(EngineType.class);

        static {
            MAP.put(COMBUSTION, new CombustionEngine());
            MAP.put(ELECTRIC, new ElectricEngine());
        }
    }

    void start();

    static Engine getEngine(EngineType type) {
        return EngineType.MAP.get(type);
    }

}
like image 96
Martin Avatar answered Sep 29 '22 06:09

Martin


You can define the factory as returning the Interface but internally it creates a concrete class.

For example:

public Interface I { }

private class Impl implements I {
}

I buildI() {
    return new Impl();
}

The trick is to create the implementations with package private (or even if they are inner classes private) constructors and then only the factory can build them.

The power of this method is that the factory can build the appropriate implementation depending on the requirements and that all happens invisibly to the user. For example when you create an EnumSet using the factory there are multiple internal implementations depending on how many entries there are in the Enum that the EnumSet is being built for. A super-fast version using bitfields on a long for Enums with less than 64 entries, a slower version for longer enumerations.

To specify the interface for a factory all you need to do is:

public interface Factory {
   I buildI();
}

Now people can call you with setFactory(new FactoryImpl()); you can then call factory.buildI() and their code then returns the concrete implementation.

You can take this a step further and use Generics:

public interface GenericFactory<T> {
    T buildInstance();
}

And then your setFactory becomes:

public void setFactory(GenericFactory<I> factory);

To create a factory they do:

public class FactoryImpl implements GenericFactory<I> {
     @override
     I buildInstance() {
        return new impl();
     }
}

But now you can use that same factory class for absolutely anything that needs a factory, just change the generics requirement.

The reason it can call the private constructor is very simple - it's declared in the same class!

Inside one Java file you can create the class with the private constructor. You then define the static method inside the class and even though it is static it still has the privileges required to access the constructor.

If the factory and implementation are in separate classes then they will be placed in the same package and the method made package private instead of private.

like image 42
Tim B Avatar answered Sep 29 '22 04:09

Tim B