Factory methods java example

Паттерны проектирования: FactoryMethod

Java-университет

 Паттерны проектирования: FactoryMethod - 1

Привет! Сегодня мы продолжим изучать паттерны проектирования и поговорим о фабричном методе (FactoryMethod). Ты узнаешь, что это такое и для решения каких задач подходит данный шаблон. Мы рассмотрим этот паттерн проектирования на практике и изучим его структуру. Чтобы все изложенное было тебе понятно, необходимо разбираться в следующих темах:

  1. Наследование в Java.
  2. Абстрактные методы и классы в Java.

Какую проблему решает фабричный метод

  • седаны
  • универсалы
  • купе
  • седаны AutoRush
  • универсалы AutoRush
  • купе AutoRush
  • седаны OneAuto
  • универсалы OneAuto
  • купе OneAuto

Немного о шаблоне фабрика

Напомню: мы построили с тобой небольшую виртуальную кофейню. В ней мы с помощью простой фабрики научились создавать различные виды кофе. Сегодня будем дорабатывать данный пример. Давай вспомним, как выглядела наша кофейня с простой фабрикой. У нас был класс кофе:

 public class Coffee < public void grindCoffee()< // перемалываем кофе >public void makeCoffee() < // делаем кофе >public void pourIntoCup() < // наливаем в чашку >> 
 public class Americano extends Coffee <> public class Cappuccino extends Coffee <> public class CaffeLatte extends Coffee <> public class Espresso extends Coffee <> 
 public class SimpleCoffeeFactory < public Coffee createCoffee (CoffeeType type) < Coffee coffee = null; switch (type) < case AMERICANO: coffee = new Americano(); break; case ESPRESSO: coffee = new Espresso(); break; case CAPPUCCINO: coffee = new Cappuccino(); break; case CAFFE_LATTE: coffee = new CaffeLatte(); break; >return coffee; > > 
 public class CoffeeShop < private final SimpleCoffeeFactory coffeeFactory; public CoffeeShop(SimpleCoffeeFactory coffeeFactory) < this.coffeeFactory = coffeeFactory; >public Coffee orderCoffee(CoffeeType type) < Coffee coffee = coffeeFactory.createCoffee(type); coffee.grindCoffee(); coffee.makeCoffee(); coffee.pourIntoCup(); System.out.println("Вот ваш кофе! Спасибо, приходите еще!"); return coffee; >> 

Модернизация простой фабрики

  • в итальянской кофейне мы будем использовать исключительно итальянские кофейные бренды, с особым помолом и прожаркой.
  • в американской порции будут чуточку больше, и к каждому заказу будем подавать плавленный зефир — маршмеллоу.
 public class Americano extends Coffee <> public class Cappuccino extends Coffee <> public class CaffeLatte extends Coffee <> public class Espresso extends Coffee <> 
 public class ItalianStyleAmericano extends Coffee <> public class ItalianStyleCappucino extends Coffee <> public class ItalianStyleCaffeLatte extends Coffee <> public class ItalianStyleEspresso extends Coffee <> public class AmericanStyleAmericano extends Coffee <> public class AmericanStyleCappucino extends Coffee <> public class AmericanStyleCaffeLatte extends Coffee <> public class AmericanStyleEspresso extends Coffee <> 

Раз мы желаем сохранить действующую бизнес-модель неизменной, нам хочется, чтобы метод orderCoffee(CoffeeType type) претерпел минимальное количество изменений. Взглянем на него:

 public Coffee orderCoffee(CoffeeType type)

Какие варианты у нас есть? Мы ведь уже умеем писать фабрику? Самое простое, что сходу приходит в голову — написать две аналогичные фабрики, а затем передавать нужную реализацию в нашу кофейню в конструкторе. Тогда класс кофейни не изменится. Для начала нам нужно создать новый класс-фабрику, унаследоваться от нашей простой фабрики и переопределить метод createCoffee (CoffeeType type) . Напишем фабрики для создания кофе в итальянском и американском стилях:

 public class SimpleItalianCoffeeFactory extends SimpleCoffeeFactory < @Override public Coffee createCoffee (CoffeeType type) < Coffee coffee = null; switch (type) < case AMERICANO: coffee = new ItalianStyleAmericano(); break; case ESPRESSO: coffee = new ItalianStyleEspresso(); break; case CAPPUCCINO: coffee = new ItalianStyleCappuccino(); break; case CAFFE_LATTE: coffee = new ItalianStyleCaffeLatte(); break; >return coffee; > > public class SimpleAmericanCoffeeFactory extends SimpleCoffeeFactory < @Override public Coffee createCoffee (CoffeeType type) < Coffee coffee = null; switch (type) < case AMERICANO: coffee = new AmericanStyleAmericano(); break; case ESPRESSO: coffee = new AmericanStyleEspresso(); break; case CAPPUCCINO: coffee = new AmericanStyleCappuccino(); break; case CAFFE_LATTE: coffee = new AmericanStyleCaffeLatte(); break; >return coffee; > > 

Теперь мы можем передавать нужную реализацию фабрики в CoffeeShop. Давай посмотрим, как бы выглядел код для заказа кофе из разных кофеен. Например, капучино в итальянском и американском стилях:

Читайте также:  Games on website html code

Мы создали две различные кофейни, передав в каждую нужную фабрику. С одной стороны, мы достигли поставленной задачи, но с другой стороны. Что-то скребет неуемную душу предпринимателя… Давай разбираться, что не так. Во-первых, обилие фабрик. Это что, каждый раз теперь под новую точку свою фабрику создавать и вдобавок следить за тем, чтобы при создании кофейни в конструктор передавалась нужная фабрика? Во-вторых, это все еще простая фабрика. Просто немного модернизированная. Мы тут все-таки новый паттерн изучаем. В-третьих, а что, нельзя что ли по-другому? Вот было бы классно, если бы мы могли локализовать все вопросы по приготовлению кофе внутри класса CoffeeShop , связав процессы по созданию кофе и обслуживанию заказа, но при этом сохранив достаточную гибкость, чтобы делать кофе в различных стилях. Ответ — да, можно. Это называется шаблон проектирования фабричный метод.

От простой фабрики к фабричному методу

  1. Вернем метод createCoffee(CoffeeType type) в класс CoffeeShop .
  2. Данный метод сделаем абстрактным.
  3. Сам класс CoffeeShop станет абстрактным.
  4. У класса CoffeeShop появятся наследники.
 public abstract class Coffee < public void makeCoffee()< // делаем кофе >public void pourIntoCup() < // наливаем в чашку >> 
 public abstract class CoffeeShop < public Coffee orderCoffee(CoffeeType type) < Coffee coffee = createCoffee(type); coffee.makeCoffee(); coffee.pourIntoCup(); System.out.println("Вот ваш кофе! Спасибо, приходите еще!"); return coffee; >protected abstract Coffee createCoffee(CoffeeType type); > 

Шаг 3. Создадим итальянскую кофейню, класс-потомок абстрактной кофейни. В нем мы реализуем метод createCoffee(CoffeeType type) с учетом итальянской специфики.

 public class ItalianCoffeeShop extends CoffeeShop < @Override public Coffee createCoffee (CoffeeType type) < Coffee coffee = null; switch (type) < case AMERICANO: coffee = new ItalianStyleAmericano(); break; case ESPRESSO: coffee = new ItalianStyleEspresso(); break; case CAPPUCCINO: coffee = new ItalianStyleCappuccino(); break; case CAFFE_LATTE: coffee = new ItalianStyleCaffeLatte(); break; >return coffee; > > 
 public class AmericanCoffeeShop extends CoffeeShop < @Override public Coffee createCoffee (CoffeeType type) < Coffee coffee = null; switch (type) < case AMERICANO: coffee = new AmericanStyleAmericano(); break; case ESPRESSO: coffee = new AmericanStyleEspresso(); break; case CAPPUCCINO: coffee = new AmericanStyleCappuccino(); break; case CAFFE_LATTE: coffee = new AmericanStyleCaffeLatte(); break; >return coffee; > > 

Поздравляю тебя. Мы только что реализовали шаблон проектирования фабричный метод на примере нашей кофейни.

Принцип работы фабричного метода

 Паттерны проектирования: FactoryMethod - 2

Теперь рассмотрим подробнее, что же у нас получилось. На диаграмме ниже — получившиеся классы. Зеленые блоки — классы создатели, голубые — классы продукты. Какие выводы можно сделать?

  1. Все продукты — реализации абстрактного класса Coffee .
  2. Все создатели — реализации абстрактного класса CoffeeShop .
  3. Мы наблюдаем две параллельные иерархии классов:
    • Иерархия продуктов. Мы видим итальянских потомков и американских потомков
    • Иерархия создателей. Мы видим итальянских потомков и американских потомков
  4. У суперкласса CoffeeShop нет информации о том, какая конкретно реализация продукта ( Coffee ) будет создана.
  5. Суперкласс CoffeeShop делегирует создание конкретного продукта своим потомкам.
  6. Каждый потомок класса CoffeeShop реализует фабричный метод createCoffee() в соответствии со своей спецификой. Иными словами, внутри реализаций классов-создателей принимается решение о приготовлении конкретного продукта, исходя из специфики класса создателя.

Теперь ты готов к определению паттерна фабричный метод . Паттерн фабричный метод определяет интерфейс создания объекта, но позволяет субклассам выбрать класс создаваемого экземпляра. Таким образом, Фабричный метод делегирует операцию создания экземпляра субклассам. В общем, не столь важно помнить определение, как понимать, как все работает.

Структура фабричного метода

 Паттерны проектирования: FactoryMethod - 3

На схеме выше представлена общая структура паттерна фабричный метод. Что еще здесь важно?

  1. Класс Creator содержит реализации всех методов, взаимодействующих с продуктами, кроме фабричного метода.
  2. Абстрактный метод factoryMethod() должен быть реализован всеми потомками класса Creator .
  3. Класс ConcreteCreator реализует метод factoryMethod() , непосредственно производящий продукт.
  4. Данный класс отвечает за создание конкретных продуктов. Это единственный класс с информацией о создании этих продуктов.
  5. Все продукты должны реализовывать общий интерфейс — быть потомками общего класса-продукта. Это нужно, чтобы классы, использующие продукты, могли оперировать ими на уровне абстракций, а не конкретных реализаций.

Домашнее задание

Итак, сегодня мы провели довольно большую работу и изучили паттерн проектирования фабричный метод. Самое время закрепить пройденный материал! Задание 1. Поработать над открытием еще одной кофейни. Она может быть выполнена в английском стиле или испанском. Или даже в стиле космического корабля. Добавим пищевых красителей в кофе, чтоб блестело, и вообще, кофе будет просто космос! Задание 2. На прошлой лекции у тебя было задание создать виртуальный суши-бар либо виртуальную пиццерию. Твоя задача — не стоять на месте. Сегодня ты узнал, как с помощью шаблона фабричный метод можно придти к успеху. Пора воспользоваться этими знаниями и расширить собственный бизнес 😉

Источник

Factory method design pattern in Java

It is a creational design pattern that talks about the creation of an object. The factory design pattern says that define an interface ( A java interface or an abstract class) for creating object and let the subclasses decide which class to instantiate. The factory method in the interface lets a class defers the instantiation to one or more concrete subclasses. Since these design patterns talk about the instantiation of an object and so it comes under the category of creational design pattern. If we notice the name Factory method, that means there is a method which is a factory, and in general, factories are involved with creational stuff and here with this, an object is being created. It is one of the best ways to create an object where object creation logic is hidden from the client. Now Let’s look at the implementation.

Implementation:

  1. Define a factory method inside an interface.
  2. Let the subclass implements the above factory method and decides which object to create.
  3. In Java, constructors are not polymorphic, but by allowing subclass to create an object, we are adding polymorphic behavior to the instantiation. In short, we are trying to achieve Pseudo polymorphism by letting the subclass to decide what to create, and so this Factory method is also called a virtual constructor.

Let us try to implement it with a real-time problem and some coding exercises.

Problem Statement: Consider we want to implement a notification service through email, SMS, and push notifications. Let’s try to implement this with the help of the factory method design pattern. First, we will design a UML class diagram for this.

In the above class diagram, we have an interface called Notification, and three concrete classes are implementing the Notification interface. A factory class NotificationFactory is created to get a Notification object. Let’s jump into the coding now.

Create Notification interface

Источник

Оцените статью