В моем предыдущем посте о шаблонном шаблонном методе я показал, как можно использовать лямбда-выражения и методы по умолчанию . В этой статье я расскажу о шаблоне фабричного метода и узнаю, как можно использовать ссылки на методы, еще одну функцию, добавленную в 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 wayDriving a car...Cleaning a car...Handling a new vehicle. Pre lambda wayDriving 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.