In my previous post about the Template Method pattern, I showed how one can leverage lambda expression and default methods. In this post I will explore about factory method pattern and see how one can leverage method references, another feature added in Java 8 alongside lambda expressions.
Lets consider a Vehicle
interface and 2 of its implementations namely Car
and Vehicle
.
interface Vehicle{ public void drive(); public void clean(); } class Car implements Vehicle{ @Override public void drive(){ System.out.println("Driving a car..."); } @Override public void clean(){ System.out.println("Cleaning a car..."); } } class Bus implements Vehicle{ @Override public void drive(){ System.out.println("Driving a Bus..."); } @Override public void clean(){ System.out.println("Cleaning a Bus..."); } }
And to drive()
and clean()
the Vehicle
we would use a VehicleDriver
.
Implementation in Java 7 and before
Lets consider the implementation and of VehicleDriver from a Pre Java 8 point of view i.e Java 7 and before.
abstract class VehicleDriver{ public abstract Vehicle getVehicle(); public void driveVehicle(){ getVehicle().drive(); } public void cleanVehicle(){ getVehicle().clean(); } } class CarDriver extends VehicleDriver{ @Override public Vehicle getVehicle(){ return new Car(); } } class BusDriver extends VehicleDriver{ @Override public Vehicle getVehicle(){ return new Bus(); } }
In the above VehicleDriver
implementation the getVehicle()
method is the factory method which is overridden by the CarDriver
and Busdriver
to return Car
and Bus
instances respectively. In this way the programmer would be more concerned about using the VehicleDriver
abstraction and need not be concerned about its different implementations. There’s another related pattern: Factory Pattern which is slightly different from this pattern and readers should not confuse this with that pattern. Ok, lets quickly look at how this can be used before proceeding to its Java 8 variant:
public class FactoryMethodPattern { public static void main(String[] args) { handleVehicle(new CarDriver()); handleVehicle(new BusDriver()); } static void handleVehicle(VehicleDriver2 vDriver){ System.out.println("Handling a new vehicle. Pre lambda way"); vDriver.driveVehicle(); vDriver.cleanVehicle(); } }
The output would be:
Handling a new vehicle. Pre lambda way Driving a car... Cleaning a car... Handling a new vehicle. Pre lambda way Driving a Bus... Cleaning a Bus...
Leveraging Java 8
Firstly we dont need an abstract VehicleDriver
and its 2 different implementation. Instead we make use of Interfaces with Default methods to create the VehicleDriver
abstraction as shown below:
interface VehicleDriver{ public Vehicle getVehicle(); public default void driveVehicle(){ getVehicle().drive(); } public default void cleanVehicle(){ getVehicle().clean(); } }
Now lets come to the interesting part- Using Method references instead of creating different implementation of the VehicleDriver
. These method references provide a way for the code to get the required instance of Car
or Bus
class without going into the hassles of overriding the getVehicle()
method. Confused? Curious? Lets look at how we can achieve that:
public class FactoryMethodPatternLambda { public static void main(String[] args) { handleVehicle(Car::new); handleVehicle(Bus::new); } static void handleVehicle(VehicleDriver vDriver){ System.out.println("Handling a new vehicle..."); vDriver.driveVehicle(); vDriver.cleanVehicle(); } }
And the output for this would be:
Handling a new vehicle... Driving a car... Cleaning a car... Handling a new vehicle... Driving a Bus... Cleaning a Bus...
We just provided the handleVehicle
method a Vehicle to handle and didn’t worry about how its being handled or who’s handling it. But in the Java 7 and before implementation we had to be aware that there is some VehicleDriver
abstract class and then we had to override its some method and then create instance of that extended class. My main intention by showing this example is that one can leverage Java 8 features to create cleaner and easy to use APIs. But with all new features comes the learning curve.
Note: In both the above implementations the common part is the Vehicle
, Car
, Bus
classes which are used by both Java 7 and Java 8 implementations.
Categories: Java
I’m not sure I understand the difference between implementing an interface with default methods and extending an abstract class with with a couple of concrete methods and an abstract one?
Not much. I need not clutter up with different extensions of the Abstract class for supporting different Vehicles where in the task would be just to override the getVehicle(). Instead I can use an interface with default method and let the calling program pass in the factory i.e pass in the way to get an instance of different Vehicle ( in this case a method reference like Car::new, Bus::new, Truck::new and so on)
I dont really understand the passing of the arguments to handleVehicle(Car::new) With Car::new you are passing a reference to Car, dont you? and handleVehicle expects a VehicleDriver . So how does this work?
The method references – Car::new is actually creating an implementation of Supplier functional interface (http://blog.sanaulla.info/2013/04/02/supplier-interface-in-java-util-function-package-in-java-8/). The fact that VehicleDiver is a functional interfaces(http://blog.sanaulla.info/2013/03/21/introduction-to-functional-interfaces-a-concept-recreated-in-java-8/) it can be be represented by either a lambda expression or a method reference. In this case we are using a method reference(Car::new) to represent the VehicleDriver functional interface.
And how can we see that VehicleDriver is a functional interface here?
HI,
Nice piece of information shared . I am planning to go for online training on java so i watched lots of videos on youtube and also searched and came across http://www.wiziq.com/course/12145-the-6-week-complete-java-primer-with-training-certificate i don’t know weather this is going to work for me or not . So wanted to ask has anybody studied from this site? I am really confused should i go for online training or not. Other guidance will be very helpful …..
Short clarification: Car::new will actually not create an instance of Supplier, but rather an instance of VehicleDriver, which is the functional interface required by the handleVehicle method.
This is really very similar to the Template pattern. Note that the cost of pulling everything up into the VehicleDriver interface is to require every vehicle driver (even those not created through lambdas) to have a public getVehicle() method. The transformation would not have worked had you formulated the Java 7 example in such a way as to have a protected abstract getVehicle() method, which would have been more in the spirit of the Factory Method pattern.
I guess the upshot is that Java 8 has not become a functional language. Although lambdas are very helpful and one can do nice things with them, good old OO design principles (and patterns) still apply in many ways.
I could imagine more fruitful applications of lambdas in patterns that require the combination or chaining of fine-grained behavior, like Adapter or Decorator being implemented using functional composition, but I haven’t yet looked at that in detail. Have you?
What is the explanation of the method getVehicle() in the VehicleDriver interface in the Java 8 example? There must be some kind of “magic” bound to this name, because refactoring it to another name breaks the code with a java.lang.AbstractMethodError.