Шаблони дизайну: Фабрика проти заводського методу проти абстрактного заводу


183

Я читав шаблони дизайну з веб-сайту

Там я читав про «Фабрика», «Фабричний метод» та «Фабрика абстрактних», але вони настільки заплутані, я не зрозуміла у визначенні. Відповідно до визначень

Фабрика - створює об'єкти, не піддаючи клієнту логіку ідентифікації та посилається на новостворений об'єкт через загальний інтерфейс. Це спрощена версія заводського методу

Фабричний метод - визначає інтерфейс для створення об'єктів, але дозволяйте підкласам вирішувати, який клас інстанціювати і посилається на новостворений об'єкт через загальний інтерфейс.

Abstract Factory - пропонує інтерфейс для створення сімейства пов'язаних об'єктів, не чітко вказуючи їх класи.

Я також роздивився інші потоки stackoverflow щодо методу абстрактного заводу проти фабрики, але діаграми UML, намальовані там, роблять моє розуміння ще гіршим.

Хто-небудь, будь ласка, скажіть мені

  1. Чим ці три візерунки відрізняються один від одного?
  2. Коли використовувати який?
  3. А також, якщо можливо, будь-які приклади java, пов'язані з цими зразками?

3
Поки я шукав відповіді приблизно на те саме питання, що і в ОП, я знайшов цю статтю: Від фабрики до фабричного методу . Він забезпечує розуміння шляхом еволюції зразкового проекту (заводський метод, зазначений у назві, є одним із еволюційних етапів).
Нік Алексєєв

Відповіді:


251

Усі три типи заводу роблять те саме: вони є «розумним конструктором».

Скажімо, ви хочете створити два види фруктів: яблучний та апельсиновий.

Заводська

Фабрика "виправлена", оскільки у вас є лише одна реалізація без підкласифікації. У цьому випадку у вас буде такий клас:

class FruitFactory {

  public Apple makeApple() {
    // Code for creating an Apple here.
  }

  public Orange makeOrange() {
    // Code for creating an orange here.
  }

}

Випадок використання: Створення Apple або Orange - це занадто складно, щоб обробляти в конструкторі будь-який.

Фабричний метод

Фабричний метод, як правило, використовується, коли ви маєте загальну обробку в класі, але хочете змінити, який саме фрукт ви використовуєте. Так:

abstract class FruitPicker {

  protected abstract Fruit makeFruit();

  public void pickFruit() {
    private final Fruit f = makeFruit(); // The fruit we will work on..
    <bla bla bla>
  }
}

... тоді ви можете повторно використовувати загальну функціональність FruitPicker.pickFruit(), застосовуючи заводський метод у підкласах:

class OrangePicker extends FruitPicker {

  @Override
  protected Fruit makeFruit() {
    return new Orange();
  }
}

Анотація заводу

Абстрактна фабрика зазвичай використовується для таких речей, як ін'єкція / стратегія залежності, коли ви хочете мати можливість створити цілу групу об'єктів, які повинні бути "одного виду" та мати деякі загальні базові класи. Ось неясний приклад, пов'язаний з фруктами. Приклад використання тут полягає в тому, що ми хочемо переконатися, що ми випадково не використовуємо OrangePicker в Apple. Поки ми отримуємо наші фрукти і збирач з тієї ж фабрики, вони будуть відповідати.

interface PlantFactory {

  Plant makePlant();

  Picker makePicker(); 

}

public class AppleFactory implements PlantFactory {
  Plant makePlant() {
    return new Apple();
  }

  Picker makePicker() {
    return new ApplePicker();
  }
}

public class OrangeFactory implements PlantFactory {
  Plant makePlant() {
    return new Orange();
  }

  Picker makePicker() {
    return new OrangePicker();
  }
}

8
+1 Це відповідь, яка найбільше схожа на моє розуміння цих моделей. Додавання прикладів виклику коду (Клієнта) також допоможе? Питання, яке мене дуже турбує, це: чи можна сказати, що абстрактний заводський зразок - це просто заводський розширений за допомогою фабричного методу (якщо це правда, я зрозумів на цю тему)?
croraf

9
Це приклад, який я витратив на пошуки років.
Тацтінго

Це фантастичне пояснення! Дякую!
Андре Андраде

@ AndréAndrade Як викликати заводський метод ? Невеликий зразок коду pls :) Це очистить сумніви щодо його використання
Arnab Dutta

25
  1. Чим ці три візерунки відрізняються один від одного?

Фабрика: створює об'єкти, не піддаючи клієнту логіку інстанції.

Заводський метод: визначте інтерфейс для створення об’єкта, але нехай підкласи вирішують, який клас інстанціювати. Фабричний метод дозволяє відкладати екземпляри класу для підкласів

Анотація заводу: надає інтерфейс для створення сімей пов’язаних або залежних об'єктів, не вказуючи їх конкретні класи.

Шаблон AbstractFactory використовує композицію для делегування відповідальності за створення об'єкта іншому класу, тоді як шаблон дизайну методу Фабрики використовує успадкування та для створення об'єкта покладається на похідний клас або підклас

  1. Коли використовувати який?

Фабрика: Клієнту просто потрібен клас і не байдуже, яку конкретну реалізацію він отримує.

Фабричний метод: Клієнт не знає, які конкретні класи потрібно буде створити під час виконання, але просто хоче отримати клас, який зробить цю роботу.

AbstactFactory: Коли вашій системі потрібно створити декілька сімейств продуктів або ви хочете надати бібліотеку продуктів, не піддаючи деталей реалізації.

Абстрактні фабричні класи часто реалізуються за допомогою Фабричного методу. Заводські методи зазвичай викликаються у методах шаблонів.

  1. А також, якщо можливо, будь-які приклади java, пов'язані з цими зразками?

Фабрика та FactoryMethod

Намір:

Визначте інтерфейс для створення об'єкта, але нехай підкласи вирішують, який клас інстанціювати. Заводський метод дозволяє класу відкладати екземпляр для підкласів.

Діаграма UML :

введіть тут опис зображення

Продукт: Він визначає інтерфейс об'єктів, створених заводським методом.

ConcreteProduct: реалізує інтерфейс продукту

Творець: оголошує заводський метод

ConcreateCreator: реалізує заводський метод для повернення екземпляра ConcreteProduct

Постановка проблеми: Створіть Фабрику ігор за допомогою заводських методів, яка визначає ігровий інтерфейс.

Фрагмент коду:

Фабричний візерунок. Коли використовувати заводські методи?

Порівняння з іншими шаблонами оголошень:

  1. Розробка дизайну починається з заводського методу (менш складний, більш настроюваний, підкласи розповсюджуються) та розвивається у напрямку абстрактного заводу, прототипу чи конструктора (більш гнучкий, складніший), оскільки дизайнер виявляє, де потрібна більша гнучкість

  2. Абстрактні фабричні класи часто реалізовуються за допомогою заводських методів , але вони також можуть бути реалізовані за допомогою прототипу

Посилання для подальшого читання: Шаблони дизайну джерел


Чи не слід для заводського методу визначати суперклас?
Тоні Лін

21

Фабрика - окремий заводський клас для створення складного об'єкта.

Наприклад: клас FruitFactory для створення об'єкта Fruit

class FruitFactory{

public static Fruit getFruit(){...}

}

Фабричний метод - Замість цілого окремого класу для фабрики, просто додайте один метод у цей клас як сам завод.

Наприклад:

Calendar.getInstance() (Java's Calendar)

Абстрактний заводський метод - фабрика заводу

Наприклад: Скажімо, ми хочемо побудувати фабрику для комп'ютерних деталей. Тож існує кілька типів комп'ютерів, таких як Ноутбук, Настільний ПК, Сервер.

Тому для кожного типу комп’ютерів нам потрібна фабрика. Тож ми створюємо одну фабрику високих рівнів фабрик, як нижче

ComputerTypeAbstractFactory.getComputerPartFactory(String computerType) ---> This will return PartFactory which can be one of these ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

Тепер ці 3 самі знову фабрики. (Ви матимете справу з самим PartFactory, але під кришкою буде окрема реалізація на основі того, що ви надали на абстрактній фабриці)

  Interface-> PartFactory. getComputerPart(String s), 
Implementations -> ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

Usage:
new ComputerTypeAbstractFactory().getFactory(“Laptop”).getComputerPart(“RAM”)

EDIT: відредаговано, щоб надати точні інтерфейси для абстрактної фабрики відповідно до заперечень у коментарях.


1
Ідея цього полягала ComputerFactoryб у тому, що у вас є загальний інтерфейс створення ( getScreen(); getKeyboard(); getDiskdrive(); ...), а не інтерфейс для типу комп'ютера, як ви пропонуєте. Ви можете відчути проблему з дизайном, якщо в одному і тому ж самому слові два рази використовувати одне і те ж слово: Laptop Factory.get Laptop Part ().
xtofl

Ні, ні ні, не йдіть саме по коду. Це була лише анологія для розуміння. Якщо ви хочете точного прикладу з інтерфейсами, ось він. Об'єкти: Інтерфейс -> ComputerPart, реалізація -> ОЗУ, HDD, Фабрика процесорів: Інтерфейс-> PartFactory. getComputerPart (String s), Реалізації -> ServerPartFactory, LaptopPartFactory, DesktopPartFactory. Анотація заводу: ComputerType.getPartFactory ("String s") Використання: новий ComputerType (). GetFactory ("Ноутбук"). GetComputerPart ("ОЗУ")
Ravi K

2
Я оновив відповідь, щоб подбати про вашу турботу. Насправді абстрактна фабрика - це не що інше, як факт лише фабрики. Я наводив попередній приклад лише для довідки (припускаючи, що читачі будуть дбати про інтерфейси під час фактичної реалізації). Все ж дякую за повідомлення. Це завжди добре вдосконалювати. :)
Ravi K

Ні, abstract Factoryце не фабрика фабрики ... Це abstract classабо interfaceздатна створити об'єкт, який буде реалізований / розширений на різних конкретних фабриках. Детальну інформацію про код див. У прийнятій відповіді. І, будь ласка, видаліть або відредагуйте відповідь відповідно.
Julien__

Мені подобається пояснення фабричного методу, яке досить стисло, щоб розкрити, чому його так називають. У цій схемі фабрика є методом, а не класом, який, як правило, не є допоміжною утилітою, що групує методи опису, але має значення самостійно. Інші більш детальні відповіді, на жаль, пропустили це питання.
wlnirvana

11

Кожна модель дизайну процвітає, щоб не торкнутися написаного, робочого коду. Всі ми знаємо, що коли ми торкнемося робочого коду, виникають дефекти в існуючих робочих потоках, і потрібно зробити набагато більше тестування, щоб ми нічого не порушили.

Фабричний візерунок створює об'єкти на основі вхідних критеріїв, таким чином гарантуючи, що вам не потрібно писати код, наприклад, якщо це потім створити цей своєрідний об'єкт ще цей добрий об’єкт. Хорошим прикладом цього є туристичний веб-сайт. Веб-сайт для подорожей може надавати лише подорожі (рейс, поїзд, автобус) або / та надавати готелі або / та надавати туристичні туристичні пакети. Тепер, коли користувач вибирає наступний, веб-сайт повинен вирішити, які об’єкти йому потрібно створити. Чи слід створити лише об’єкт подорожі чи готелю.

Тепер, якщо ви плануєте додати до свого портфоліо ще один веб-сайт, і ви вважаєте, що використовуватиметься те саме ядро, наприклад, автомобільний веб-сайт, який зараз здійснює пошук кабіни та здійснює платежі в Інтернеті, ви можете використовувати абстрактну фабрику в основі. Таким чином, ви можете просто перебратися на ще одну фабрику кабін і авто.

Обидві фабрики не мають нічого спільного один з одним, тому її гарний дизайн підтримує їх у різних заводських.

Сподіваюсь, це зараз зрозуміло. Вивчіть веб-сайт ще раз, маючи на увазі цей приклад, сподіваємось, що це допоможе. І я дуже сподіваюся, що я правильно представив схеми :).


3

Для цієї відповіді я посилаюся на книгу "Банда чотирьох".

У книзі немає визначень «Фабрика», «Проста фабрика» і «Віртуальна фабрика». Зазвичай, коли люди говорять про "заводський" шаблон, вони можуть говорити про щось, що створює певний об'єкт класу (але не "модель" будівельника); вони можуть або не можуть посилатися на "заводський метод" або "абстрактний завод". Будь-хто може впровадити "Фабрику" так, як не хоче, оскільки це не формальний термін (майте на увазі, що деякі люди \ компанії \ громади можуть мати свій власний словник).

Книга містить лише визначення понять «Абстрактний завод» та «Фабричний метод».

Ось визначення з книги та коротке пояснення, чому обидва можуть бути настільки заплутаними. Я пропускаю приклади коду, тому що ви можете їх знайти в інших відповідях:

Фабричний метод (GOF) : визначте інтерфейс для створення об’єкта, але нехай підкласи вирішують, який клас інстанціювати. Заводський метод дозволяє класу відкладати екземпляри для підкласів.

Анотація заводу (GOF) : надайте інтерфейс для створення сімей пов’язаних або залежних об'єктів, не вказуючи їх конкретні класи.

Джерело плутанини : Часто можна назвати клас, який використовувався в шаблоні "Фабричний метод" як "Фабричний". Цей клас є абстрактним за визначенням. Ось чому легко назвати цей клас «абстрактною фабрикою». Але це лише назва класу; не слід плутати його з шаблоном "Абстрактний завод" (назва класу! = назва шаблону). Шаблон "Абстрактний завод" відрізняється - в ньому не використовується абстрактний клас; він визначає інтерфейс (не обов'язково інтерфейс мови програмування) для створення частин більшого об'єкта або об'єктів, які пов'язані один з одним або повинні бути створені певним чином.


2
AbstractProductA, A1 and A2 both implementing the AbstractProductA
AbstractProductB, B1 and B2 both implementing the AbstractProductB

interface Factory {
    AbstractProductA getProductA(); //Factory Method - generate A1/A2
}

Використовуючи заводський метод, користувач може створити A1 або A2 з AbstractProductA.

interface AbstractFactory {
    AbstractProductA getProductA(); //Factory Method
    AbstractProductB getProductB(); //Factory Method
}

Але абстрактний завод має більше 1 фабричного методу (наприклад: 2 заводські методи), використовуючи ці заводські методи, він створить набір об'єктів / пов'язаних з ними об’єктів. Використовуючи абстрактну фабрику, користувач може створити об'єкти A1, B1 з AbstractProductA, AbstractProductB


0

Ніхто не цитував оригінальну книгу " Шаблони дизайну: елементи багаторазового об'єктно-орієнтованого програмного забезпечення" , яка дає відповідь у перших двох параграфах розділу "Обговорення креативних шаблонів" (акцент мій):

Існує два загальних способи параметризації системи за класами об'єктів, які вона створює. Один із способів - це підклас класу, який створює об'єкти; це відповідає використанню схеми заводського методу (107). Основним недоліком такого підходу є те, що він може вимагати нового підкласу просто для зміни класу продукту. Такі зміни можуть каскадувати. Наприклад, коли створювач продукту сам створений фабричним методом, вам доведеться також перекрити його творця.

Інший спосіб параметризації системи більше спирається на склад об'єкта : Визначте об'єкт, який відповідає за знання класу об'єктів продукту, і зробіть його параметром системи. Це ключовий аспект моделей абстрактних заводів (87), Builder (97) та прототипів (117). Усі три стосуються створення нового "фабричного об'єкта", відповідальність за який полягає у створенні товарних об'єктів. Анотація Factory має заводський об'єкт, що виробляє предмети кількох класів. Builder має заводський об'єкт поступово будувати складний продукт, використовуючи відповідно складний протокол. Прототип має заводський об'єкт, що будує продукт, копіюючи об'єкт-прототип. У цьому випадку заводський об'єкт і прототип є одним і тим же об'єктом, оскільки прототип відповідає за повернення товару.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.