В моем предыдущем посте о шаблонном шаблонном методе я показал, как можно использовать лямбда-выражения и методы по умолчанию . В этой статье я расскажу о шаблоне фабричного метода и узнаю, как можно использовать ссылки на методы, еще одну функцию, добавленную в Java 8 наряду с лямбда-выражениями .
Давайте рассмотрим интерфейс Vehicle
и 2 его реализации, а именно Car
и Vehicle
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
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..." ); } } |
И чтобы drive()
и clean()
Vehicle
мы бы использовали VehicleDriver
.
Реализация в Java 7 и ранее
Давайте рассмотрим реализацию и VehicleDriver с точки зрения Pre Java 8, то есть Java 7 и ранее.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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(); } } |
В приведенной выше реализации getVehicle()
метод getVehicle()
является фабричным методом, который переопределяется CarDriver
и Busdriver
для возврата экземпляров Car
и Bus
соответственно. Таким образом, программист будет больше VehicleDriver
об использовании абстракции VehicleDriver
и не должен VehicleDriver
о его различных реализациях. Есть еще один связанный шаблон: Factory Pattern, который немного отличается от этого шаблона, и читатели не должны путать это с этим шаблоном. Хорошо, давайте быстро посмотрим, как это можно использовать, прежде чем перейти к варианту Java 8:
01
02
03
04
05
06
07
08
09
10
11
12
|
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(); } } |
Выход будет:
1
2
3
4
5
6
|
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... |
Использование Java 8
Во-первых, нам не нужен абстрактный VehicleDriver
и его 2 различные реализации. Вместо этого мы используем интерфейсы с методами по умолчанию для создания абстракции VehicleDriver
как показано ниже:
1
2
3
4
5
6
7
8
9
|
interface VehicleDriver{ public Vehicle getVehicle(); public default void driveVehicle(){ getVehicle().drive(); } public default void cleanVehicle(){ getVehicle().clean(); } } |
Теперь давайте перейдем к интересной части — Использование ссылок на VehicleDriver
вместо создания другой реализации VehicleDriver
. Эти ссылки на метод обеспечивают способ для кода получить требуемый экземпляр класса Car
или Bus
без необходимости getVehicle()
метод getVehicle()
. Смущенный? Любопытно? Давайте посмотрим, как мы можем достичь этого:
01
02
03
04
05
06
07
08
09
10
11
12
|
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(); } } |
И вывод для этого будет:
1
2
3
4
5
6
|
Handling a new vehicle... Driving a car... Cleaning a car... Handling a new vehicle... Driving a Bus... Cleaning a Bus... |
Мы просто предоставили метод handleVehicle
a Vehicle для обработки и не беспокоились о том, как он обрабатывается или кто его обрабатывает. Но в Java 7 и до реализации мы должны были знать, что существует некоторый абстрактный класс VehicleDriver
а затем мы должны были переопределить его некоторый метод и затем создать экземпляр этого расширенного класса. Мое главное намерение, демонстрируя этот пример, состоит в том, чтобы использовать возможности Java 8 для создания более понятных и простых в использовании API. Но со всеми новыми функциями приходит обучение.
Примечание. В обеих приведенных выше реализациях общей частью являются классы Vehicle
, Car
, Bus
которые используются в реализациях Java 7 и Java 8.