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
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.
state data is not normally maintained by the factory class, so they're normally static.
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.
The main disadvantage of providing only static factory methods is that classes without public or protected constructors cannot be subclassed.
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
EngineFactory
class (the traditional implementation of Factory method design pattern)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);
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With