Паттерн Фабричный метод (он же виртуальный конструктор) – порождающий шаблон проектирования, предоставляющий подклассам интерфейс для создания экземпляров некоторого класса. Таким образом фабричный метод делегирует операцию создания экземпляра подклассам. Это позволяет использовать в коде программы не специфические классы, а манипулировать абстрактными объектами на более высоком уровне.
Реализация: Мы с вами на протяжении трех статей о шаблонах проектирования неплохо справляемся с разработкой различных программ для автопроизводителей, не будем нарушать традицию. На этот раз давайте попробуем создать линии сборки машин различной комплектации с использованием паттерна «Фабричный метод». Начнем с двух абстрактных классов один для класса машин:
1 2 3 4 5 6 7 8 |
abstract class Car{ String name; List <String> accessories = new ArrayList(); public String toString(){ return "Model car: " + name + "\n" + accessories; } } |
Переменная name используется для хранения информации о типе машины – Luxury Car или Basic Car. Для хранения списка дополнительных опций комплектации используется переменная списочного типа accessories. Для удобства вывода информации о созданной машине был переопределен метод toString(), который возвращает модель машины (переменная name) и список опций комплектации (перемення accessories).
Второй абстрактный класс для сборочных линий:
1 2 3 4 |
abstract class CarFactory{ public abstract Car createCar(); } |
Как видите в нем только один абстрактный метод создания машин, который мы переопределим в подклассах. Всего у нас будет два подкласса: первый для сборочной линии люксовых машин, второй для сборочной линии базовых машин:
1 2 3 4 5 6 7 8 9 10 11 |
class LuxCarFactory extends CarFactory{ public Car createCar(){ return new LuxCar(); } } class BasicCarFactory extends CarFactory{ public Car createCar(){ return new BasicCar(); } } |
В каждом из подклассов реализован метод createCar(), который создает объект нужной машины и возвращает его. Условие шаблона «Фабричный метод» мы выполнили – делегировали создание объектов подклассам. Давайте теперь создадим сами классы машин, все они будут наследоваться от абстрактного класса Car() описанного выше:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class LuxCar extends Car{ public LuxCar(){ name = "Luxury Car"; accessories.add("Leather salon"); accessories.add("Air condition"); accessories.add("GPS"); accessories.add("Heated steering wheel"); } } class BasicCar extends Car{ public BasicCar(){ name = "Basic Car"; accessories.add("Basic salon"); accessories.add("Air condition"); } } |
В конструкторе каждого из классов мы задаем имя нашей машины и добавляем опции комплектации в переменные name и accessories соответственно, обе переменные были объявлены в абстрактном классе Car.
Задача паттерна «Фабричный метод» — перемещение создания экземпляров в подклассы
Пришло время протестировать нашу программу и посмотреть, как это все вместе работает:
1 2 3 4 5 6 7 8 9 10 11 12 |
public class Example{ public static void main(String[] args) { CarFactory myLuxFactory = new LuxCarFactory(); CarFactory myBasicFactory = new BasicCarFactory(); Car myLuxCar = myLuxFactory.createCar(); Car myBasicCar = myBasicFactory.createCar(); System.out.println(myLuxCar); System.out.println(myBasicCar); } } |
Вывод:
Model car: Luxury Car
[Leather salon, Air condition, GPS, Heated steering wheel]
Model car: Basic Car
[Basic salon, Air condition]
Первыми двумя строчками CarFactory myLuxFactory = new LuxCarFactory(); и CarFactory myBasicFactory = new BasicCarFactory(); мы создали две фабрики по производству машин или созданию объектов. Следующими двумя строчками Car myLuxCar = myLuxFactory.createCar(); и Car myBasicCar = myBasicFactory.createCar(); мы создали по машине (объекту) на соответствующих фабриках. Ну и последними двумя вывели информацию о созданных нами машинах (объектах).
У данного шаблона есть как достоинства, так и недостатки. К достоинствам можно отнести: возможность сделать более универсальный код создания объектов, не привязываясь к конкретным классам (в нашем случае LuxCar и BasicCar), и еще одно не мало важное достоинство – это возможность установить связь между параллельными иерархиями классов. Главным же недостатком этого паттерна является необходимость создавать наследника для каждого нового типа продукта.
В качестве небольшой практики попробуйте изменить метод createCar() так, чтобы он принимал в качестве параметра количество машин, которое мы хотим создать и соответственно создавал нужную нам партию машин.
Паттерн Фабричный метод полный код примера:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
package example; import java.util.ArrayList; import java.util.List; abstract class Car{ String name; List <String> accessories = new ArrayList(); public String toString(){ return "Model car: " + name + "\n" + accessories; } } abstract class CarFactory{ public abstract Car createCar(); } class LuxCarFactory extends CarFactory{ public Car createCar(){ return new LuxCar(); } } class BasicCarFactory extends CarFactory{ public Car createCar(){ return new BasicCar(); } } class LuxCar extends Car{ public LuxCar(){ name = "Luxury Car"; accessories.add("Leather salon"); accessories.add("Air condition"); accessories.add("GPS"); accessories.add("Heated steering wheel"); } } class BasicCar extends Car{ public BasicCar(){ name = "Basic Car"; accessories.add("Basic salon"); accessories.add("Air condition"); } } public class Example{ public static void main(String[] args) { CarFactory myLuxFactory = new LuxCarFactory(); CarFactory myBasicFactory = new BasicCarFactory(); Car myLuxCar = myLuxFactory.createCar(); Car myBasicCar = myBasicFactory.createCar(); System.out.println(myLuxCar); System.out.println(myBasicCar); } } |