Паттерн Абстрактная фабрика – предоставляет интерфейс создания семейств взаимосвязанных или взаимозависимых объектов без указания их конкретных классов. Шаблон реализуется созданием абстрактного класса, который представляет собой интерфейс для создания компонентов системы (например, для оконного интерфейса он может создавать окна и кнопки), затем пишутся классы реализующие этот интерфейс.
Применяется в случаях: когда программа должна быть независимой от процесса и типов создаваемых новых объектов; когда необходимо создать семейства или группы взаимосвязанных объектов исключая возможность одновременного использования объектов из разных этих наборов в одном контексте
Реализация: Для напишем код для комплектующих, коих у нас будет три – GPS, руль и салон. Для каждого из комплектующих создадим интерфейс:
1 2 3 4 5 6 7 8 9 10 11 |
interface CarSalon{ public abstract String toString(); } interface SteeringWheel{ public abstract String toString(); } interface GPS{ public abstract String toString(); } |
Каждый интерфейс реализован двумя классами за исключением интерфейса GPS:
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 |
class LeatherCarSalon implements CarSalon{ public String toString(){ return "Leather Salon"; } } class BasicCarSalon implements CarSalon{ public String toString(){ return "Basic Salon"; } } class HeatedSteeringWheel implements SteeringWheel{ public String toString(){ return "Heated steering wheel"; } } class BasicSteeringWheel implements SteeringWheel{ public String toString(){ return "Basic steering wheel"; } } class CarGPS implements GPS{ public String toString(){ return "GPS"; } } |
Как вы могли заметить деление классов идет на продукцию для люксовых машин и на продукцию для машин базовой комплектации, за исключением GPS который мы в базовую комплектацию не будем устанавливать ни в каком виде. В каждом из классов реализован метод toString(), который будет возвращать строковое значение установленного компонента.
С продукцией разобрались, теперь начнем работу над фабриками, которые будут производить нужные нам компоненты (создавать объекты классов компонентов). Начнем с общего интерфейса:
1 2 3 4 5 |
interface CarPartsFactory{ public abstract CarSalon addCarSalon(); public abstract SteeringWheel addSteeringWheel(); public abstract GPS addGPS(); } |
В интерфейсе три абстрактных метода, каждый из которых производит соответствующий компонент. Реализации фабрик будут тоже делиться на два типа – фабрики по производству компонентов для люксовых машин и для базовых машин:
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 |
class LuxCarPartsFactory implements CarPartsFactory{ public CarSalon addCarSalon(){ return new LeatherCarSalon(); } public SteeringWheel addSteeringWheel(){ return new HeatedSteeringWheel(); } public GPS addGPS(){ return new CarGPS(); } } class BasicCarPartsFactory implements CarPartsFactory{ public CarSalon addCarSalon(){ return new BasicCarSalon(); } public SteeringWheel addSteeringWheel(){ return new BasicSteeringWheel(); } public GPS addGPS(){ return null; } } |
Каждый из реализованных методов возвращает созданный компонент нужной детали. Обратите внимание в базовой комплектации у машин нет GPS, поэтому метод addGPS() возвращает null.
У нас есть детали, у нас есть фабрики по их производству, самое время приступить к созданию машин. Как и всегда первое, что мы создадим это общий интерфейс, в качестве общего интерфейса выступит абстрактный класс Car:
1 2 3 4 5 6 7 8 |
abstract class Car{ String name; List accessories = new ArrayList(); public String toString(){ return "Model car: " + name + "\n" + accessories; } } |
В классе присутствуют две переменных: одна для хранения названия машины (name), вторая для хранения информации о комплектующих установленных в машину (accessories). В классе так же переопределен метод toString(), который теперь сообщает название машины и из каких комплектующих она состоит.
Машин, как Вы уже догадались у нас будет две – одна люксовая, другая базовая. Создадим для них классы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class LuxCar extends Car{ public LuxCar(CarPartsFactory carPartsFactory){ name = "Luxury Car"; accessories.add(carPartsFactory.addCarSalon()); accessories.add(carPartsFactory.addSteeringWheel()); accessories.add(carPartsFactory.addGPS()); } } class BasicCar extends Car{ public BasicCar(CarPartsFactory carPartsFactory){ name = "Basic Car"; accessories.add(carPartsFactory.addCarSalon()); accessories.add(carPartsFactory.addSteeringWheel()); } } |
Вся магия данных классов происходит в конструкторе, в котором мы даем, с помощью переменной name, название нашей машине, и с помощью переменной accessories, унаследованной от абстрактного класса, создаем нашу машину из комплектующих, которые поставляет фабрика, переданная через параметр конструктора (переменная carPartsFactory).
Настало время проверить как все работает:
1 2 3 4 5 6 7 8 9 10 11 12 |
public class Example{ public static void main(String[] args) { CarPartsFactory myLuxFactory = new LuxCarPartsFactory(); CarPartsFactory myBasicFactory = new BasicCarPartsFactory(); Car myLuxCar = new LuxCar(myLuxFactory); Car myBasicCar = new BasicCar(myBasicFactory); System.out.println(myLuxCar); System.out.println(myBasicCar); } } |
Вывод:
Model car: Luxury Car
[Leather Salon, Heated steering wheel, GPS]
Model car: Basic Car
[Basic Salon, Basic steering wheel]
К плюсам паттерна «Абстрактная фабрика» можно отнести: изоляцию конкретных классов, простоту замены продуктов и гарантию сочетаемости классов. Из минусов стоит отметить сложность добавления поддержки нового вида продукции.
Паттерн Абстрактная фабрика полный код примера:
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
package example; import java.util.ArrayList; import java.util.List; abstract class Car{ String name; List accessories = new ArrayList(); public String toString(){ return "Model car: " + name + "\n" + accessories; } } class LuxCar extends Car{ public LuxCar(CarPartsFactory carPartsFactory){ name = "Luxury Car"; accessories.add(carPartsFactory.addCarSalon()); accessories.add(carPartsFactory.addSteeringWheel()); accessories.add(carPartsFactory.addGPS()); } } class BasicCar extends Car{ public BasicCar(CarPartsFactory carPartsFactory){ name = "Basic Car"; accessories.add(carPartsFactory.addCarSalon()); accessories.add(carPartsFactory.addSteeringWheel()); } } interface CarPartsFactory{ public abstract CarSalon addCarSalon(); public abstract SteeringWheel addSteeringWheel(); public abstract GPS addGPS(); } class LuxCarPartsFactory implements CarPartsFactory{ public CarSalon addCarSalon(){ return new LeatherCarSalon(); } public SteeringWheel addSteeringWheel(){ return new HeatedSteeringWheel(); } public GPS addGPS(){ return new CarGPS(); } } class BasicCarPartsFactory implements CarPartsFactory{ public CarSalon addCarSalon(){ return new BasicCarSalon(); } public SteeringWheel addSteeringWheel(){ return new BasicSteeringWheel(); } public GPS addGPS(){ return null; } } interface CarSalon{ public abstract String toString(); } class LeatherCarSalon implements CarSalon{ public String toString(){ return "Leather Salon"; } } class BasicCarSalon implements CarSalon{ public String toString(){ return "Basic Salon"; } } interface SteeringWheel{ public String toString(); } class HeatedSteeringWheel implements SteeringWheel{ public String toString(){ return "Heated steering wheel"; } } class BasicSteeringWheel implements SteeringWheel{ public String toString(){ return "Basic steering wheel"; } } interface GPS{ public String toString(); } class CarGPS implements GPS{ public String toString(){ return "GPS"; } } public class Example{ public static void main(String[] args) { CarPartsFactory myLuxFactory = new LuxCarPartsFactory(); CarPartsFactory myBasicFactory = new BasicCarPartsFactory(); Car myLuxCar = new LuxCar(myLuxFactory); Car myBasicCar = new BasicCar(myBasicFactory); System.out.println(myLuxCar); System.out.println(myBasicCar); } } |