Які відмінності між моделями дизайну абстрактних фабрик та заводів?


454

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

З того, що я читав, я бачу, що заводська схема методу дозволяє визначити, як створити єдиний конкретний продукт, але приховує реалізацію від клієнта, оскільки вони побачать загальний продукт. Перше моє запитання - про абстрактну фабрику. Чи є його роль дозволити створювати родини конкретних об'єктів (це може залежати від конкретної фабрики, яку ви використовуєте), а не лише один конкретний об'єкт? Чи повертає абстрактна фабрика лише один дуже великий об'єкт або багато об'єктів залежно від методів, які ви називаєте?

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

Одна відмінність між ними полягає в тому, що за абстрактним заводським зразком клас делегує відповідальність за інстанціювання об'єкта іншому об'єкту за допомогою композиції, тоді як шаблон методу Factory використовує успадкування і покладається на підклас для обробки потрібного об'єкта.

Я розумію, що шаблон заводського методу має інтерфейс Creator, завдяки якому ConcreteCreator несе відповідальність за те, який саме ConcreteProduct створити. Це що означає використання спадщини для обробки екземплярів об'єктів?

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

Будемо дуже вдячні за будь-яку допомогу, особливо з останнім питанням.



Бачити, як "створений екземпляр" з точки зору клієнта, допоможе вам зрозуміти цитату.
Картик Босе

@nawfal, відповіді в цій темі жахливі.
jaco0646

Відповіді:


494

Різниця між двома

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

Оскільки фабричний метод - це лише метод, його можна перекрити в підкласі, звідси друга половина вашої цитати:

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

Цитата передбачає, що об’єкт викликає тут власний заводський метод. Тому єдиним, що могло б змінити повернене значення, був би підклас.

Абстрактна фабрика - це об'єкт, на якому є кілька заводських методів. Дивлячись на першу половину вашої цитати:

... з малюнком абстрактного заводу клас делегує відповідальність за інстанціювання об'єкта іншому об'єкту за допомогою композиції ...

Вони говорять про те, що існує об'єкт A, який хоче зробити об'єкт Foo. Замість того, щоб робити сам об'єкт Foo (наприклад, фабричним методом), для створення об'єкта Foo вийде інший об’єкт (абстрактний завод).

Приклади коду

Щоб показати вам різницю, тут використовується заводський метод:

class A {
    public void doSomething() {
        Foo f = makeFoo();
        f.whatever();   
    }

    protected Foo makeFoo() {
        return new RegularFoo();
    }
}

class B extends A {
    protected Foo makeFoo() {
        //subclass is overriding the factory method 
        //to return something different
        return new SpecialFoo();
    }
}

І ось тут використовується абстрактна фабрика:

class A {
    private Factory factory;

    public A(Factory factory) {
        this.factory = factory;
    }

    public void doSomething() {
        //The concrete class of "f" depends on the concrete class
        //of the factory passed into the constructor. If you provide a
        //different factory, you get a different Foo object.
        Foo f = factory.makeFoo();
        f.whatever();
    }
}

interface Factory {
    Foo makeFoo();
    Bar makeBar();
    Aycufcn makeAmbiguousYetCommonlyUsedFakeClassName();
}

//need to make concrete factories that implement the "Factory" interface here

15
Це таке чудове пояснення. Але, яка найважливіша частина залишається без відповіді, а це: коли використовувати один, а коли інший шаблон?
croraf

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

2
Так правильно сказати: Фабричний метод може бути методом у всіх регулярних заняттях з різною метою. Але "Фабрика абстрактних" - це клас / об'єкт, який використовується клієнтом і ТИЛЬКО відповідає за створення деяких продуктів у сім'ї?
Hieu Nguyen

Чи вживання вами слова "Super" у "SuperFoo" означає лише особливий випадок Foo, чи це насправді означає суперклас? Як я припускав, це повинен бути підклас.
dahui

@dahui Так, це підклас. Я змінив це, SpecialFooщоб бути більш зрозумілим.
Том Даллінг

125

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

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

Фабричний метод - це просто простий метод, який використовується для створення об’єктів у класі. Зазвичай він додається в сукупний корінь ( OrderКлас має метод, який називається CreateOrderLine)

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

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

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

interface IMessageQueueFactory
{
  IMessageQueue CreateOutboundQueue(string name);
  IMessageQueue CreateReplyQueue(string name);
}

public class AzureServiceBusQueueFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new AzureMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new AzureResponseMessageQueue(/*....*/);
      }

}

public class MsmqFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new MsmqMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new MsmqResponseMessageQueue(/*....*/);
      }
}

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

Проблема HTTP-серверів полягає в тому, що нам завжди потрібна відповідь на кожен запит.

public interface IHttpRequest
{
    // .. all other methods ..

    IHttpResponse CreateResponse(int httpStatusCode);
}

Без фабричного методу користувачі HTTP-сервера (тобто програмісти) будуть змушені використовувати конкретні класи для впровадження, які заважають призначенню IHttpRequestінтерфейсу.

Тому ми вводимо заводський метод, щоб створення класу відповідей також було абстрагованим.

Підсумок

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

Слід бути обережним при використанні заводських методів, оскільки при створенні об'єктів легко порушити LSP ( принцип заміни Ліскова ).


3
Для чого нам потрібен конкретний виріб?
Andrew S

60
Тому що ніхто не хоче вкладати гроші в ідеї.
jgauffin

4
Абстрактна фабрика повинна створити більше, ніж просто Button()створити "сімейство супутніх товарів". Наприклад, канонічний приклад GoF створює ScrollBar()і Window(). Перевага полягає в тому, що абстрактна фабрика може застосовувати загальну тему у своїх кількох продуктах.
jaco0646

Яко правий. Вважайте, що обидві діаграми UML по суті є однаковими (поруч з помилкою UML-анотації Factory). В обох випадках клієнт викликає заводський метод створення одного продукту.
cobby

1
@AndrewS: щоб відповісти на ваше запитання. Якщо нам не потрібно мати різні конкретні вироби (класи) для однієї абстракції (інтерфейс), нам, мабуть, потрібен візерунок будівельника, а не заводський зразок. (краще пізно, ніж ніколи))
jgauffin

95

Різниця між моделями дизайну AbstractFactory та Factory полягає в наступному:

  • Фабричний метод використовується лише для створення одного продукту, але абстрактний завод - це створення сімей пов'язаних або залежних продуктів.
  • Шаблон « Фабричний метод» відкриває клієнту метод створення об’єкта, тоді як у випадку « Фабрика абстрактних» вони відкривають сімейство пов'язаних об’єктів, які можуть складатися з цих заводських методів.
  • Заводський метод шаблону приховує побудову одного об'єкта, тоді як абстрактний завод приховує побудову родини споріднених об'єктів. Абстрактні фабрики зазвичай реалізуються за допомогою (набору) заводських методів.
  • Абстрактний шаблон Factory використовує склад для делегування відповідальності за створення об'єкта іншому класу, тоді як шаблон дизайну Factory Method використовує успадкування та для створення об'єкта покладається на похідний клас або підклас.
  • Ідея, що стоїть за шаблоном « Фабричний метод», полягає в тому, що він допускає випадок, коли клієнт не знає, які конкретні класи потрібно буде створити під час виконання, а просто хоче отримати клас, який буде виконувати роботу, в той час як абстрактний заводський шаблон є найкраще використовувати, коли вашій системі доводиться створювати декілька сімейств продуктів або ви хочете надати бібліотеку продуктів, не піддаючи деталей реалізації.

Впровадження заводського методу: Фабричний метод UML

Реалізація абстрактних заводських моделей:

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


13
Ммм, не впевнений у абстрактному заводському прикладі. Я думаю, що фабрика форм і фабрика кольорів повинні реалізувати однакові методи. Але тоді, якщо я маю рацію, то зразок не має сенсу.
Хоакін Юрчук

4
Точки кулі правильні; однак обидві діаграми абсолютно неправильні та дуже оманливі. Дивіться діаграму нижче від @Trying для точної моделі абстрактного заводу.
jaco0646

1
я повинен погодитися, 2 діаграми дійсно дуже вводять в оману. Я бачив їх на веб-сайті tutorialspoint, і якщо чесно, я не згоден з ними на 100%. Хоча описи виглядають добре
SoftwareDeveloper

Це дуже вводить в оману.
diyoda_

50+ оновлень і діаграм дуже помиляються. Доказ того, що ти не можеш довіряти багатьом відповідям на модель дизайну.
Фурманатор

27

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

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

Діаграми UML можна знайти в книзі (GoF). Я хочу навести приклади коду, тому що я думаю, що поєднання прикладів із перших двох відповідей у ​​цій темі дасть кращу демонстрацію, ніж будь-яка відповідь поодинці. Крім того, я використовував термінологію з книги у назвах класів та методів.

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

  1. Тут найважливішим моментом є те, що абстрактна фабрика вводиться клієнту. Тому ми говоримо, що абстрактна фабрика реалізована компанією. Часто це завдання виконує завдання введення залежності; але рамки для DI не потрібні.
  2. Другий критичний момент - це те, що тут працюють конкретні заводи не є реалізацією заводських методів! Приклад коду для заводського методу подано нижче.
  3. І нарешті, третім моментом, який слід зазначити, є взаємозв'язок між продуктами: у цьому випадку черги на вихід та відповіді. Один бетонний завод виробляє черги Azure, інший - MSMQ. GoF відноситься до цього продуктового відносини як до "сім'ї", і важливо пам'ятати, що сім'я в цьому випадку не означає ієрархію класів.
public class Client {
    private final AbstractFactory_MessageQueue factory;

    public Client(AbstractFactory_MessageQueue factory) {
        // The factory creates message queues either for Azure or MSMQ.
        // The client does not know which technology is used.
        this.factory = factory;
    }

    public void sendMessage() {
        //The client doesn't know whether the OutboundQueue is Azure or MSMQ.
        OutboundQueue out = factory.createProductA();
        out.sendMessage("Hello Abstract Factory!");
    }

    public String receiveMessage() {
        //The client doesn't know whether the ReplyQueue is Azure or MSMQ.
        ReplyQueue in = factory.createProductB();
        return in.receiveMessage();
    }
}

public interface AbstractFactory_MessageQueue {
    OutboundQueue createProductA();
    ReplyQueue createProductB();
}

public class ConcreteFactory_Azure implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new AzureMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new AzureResponseMessageQueue();
    }
}

public class ConcreteFactory_Msmq implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new MsmqMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new MsmqResponseMessageQueue();
    }
}

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

  1. Найважливіший момент, який можна зрозуміти, це те ConcreteCreator , що клієнт є. Іншими словами, клієнт - це підклас, батько якого визначає factoryMethod(). Ось чому ми говоримо, що Фабричний метод реалізований Inheritance.
  2. Другий критичний момент - пам’ятати, що заводський метод шаблонів - це не що інше, як спеціалізація шаблону методу шаблону. Два візерунки мають однакову структуру. Вони відрізняються лише за призначенням. Фабричний метод є креативним (він щось будує), тоді як метод шаблону є поведінковим (він щось обчислює).
  3. І, нарешті, третій момент, який слід зазначити, - це те, що Creator(батьківський) клас викликає своє factoryMethod(). Якщо ми видалимо anOperation()з батьківського класу, залишивши позаду лише один метод, це вже не шаблон Factory Factory. Іншими словами, заводський метод не може бути реалізований з менш ніж двома методами в батьківському класі; і один повинен викликати іншого.
public abstract class Creator {
    public void anOperation() {
        Product p = factoryMethod();
        p.whatever();
    }

    protected abstract Product factoryMethod();
}

public class ConcreteCreator extends Creator {
    @Override
    protected Product factoryMethod() {
        return new ConcreteProduct();
    }
}

Різне & Різні фабричні візерунки

Майте на увазі, що, хоча GoF визначає дві різні фабричні моделі, це не єдині фабричні моделі, що існують. Вони навіть не обов'язково є найпоширенішими фабричними візерунками. Відомий третій приклад - статичний заводський зразок Джоша Блоха від ефективної Java. Книга «Шаблони дизайну головного дизайну» включає ще одну модель, яку вони називають Simple Factory.

Не потрапляйте в пастку, якщо припустити, що кожен заводський зразок повинен відповідати одному з GoF.


3
Чудова і дуже чітка відповідь на основі хороших прикладів, найкраща в цій темі ІМО.
Лука Дуда

Чудове пояснення. +1 для Фабричного методу має викликати свою абстрактну заводську точку методу. З цим пунктом все зрозуміло, не розуміючи цього пункту: якщо у нас заводський метод не посилається на нього, це означає, що його буде використовувати якийсь інший клас, який складе його, і його підкласи будуть введені, він перетвориться на абстрактний завод , різниця стає менш зрозумілою, якщо зауважити, що абстрактний заводський метод повинен бути використаний самим заводом, як шаблон методу шаблону не зрозумілий
nits.kk

Ще одне запитання-зауваження. Чи factoryMethod()завжди повинен бути protected метод у шаблоні "Фабричний метод"? (Я думаю, що так)
Ярослав Федорук

1
@YaroslavFedoruk, книга GoF дозволяє використовувати publicзаводські методи, а методу навіть не слід abstract; але важливим моментом є те, що метод призначений для успадкування, тому він не може бути (наприклад) staticабо final. Я зробив метод protectedі abstractтут, щоб виділити (необхідну) розширюваність.
jaco0646

@ nits.kk, вас може зацікавити відповідна відповідь .
jaco0646

26

Abstract Factory - це інтерфейс для створення супутніх продуктів, але Factory Method - це лише один метод. Анотація Фабрика може бути реалізована кількома фабричними методами.

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


10
Ви вже відповідав той же відповідь тут . Якщо ви вважаєте, що це питання схоже, позначте його як дублікат.
Ja͢ck

11

Розглянемо цей приклад для легкого розуміння.

Що надають телекомунікаційні компанії? Наприклад, широкосмугову, телефонну лінію та мобільний телефон, і вас попросять створити додаток, щоб пропонувати свою продукцію своїм клієнтам.

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

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

Анотація заводу , тобто, це склад інших фабрик, які відповідають за створення власної продукції, а " Фабрика абстрактних" знає, як розмістити ці продукти в більш значущому відношенні до власних обов'язків.

У цьому випадку, BundleFactoryце "Фабрика абстрактних" BroadbandFactory, " PhonelineFactoryі"MobileFactory є Factory. Щоб спростити більше, ці Заводи матимуть Заводський метод для ініціалізації окремих продуктів.

Нижче наведено зразок коду:

public class BroadbandFactory : IFactory {
    public static Broadband CreateStandardInstance() {
        // broadband product creation logic goes here
    }
}

public class PhonelineFactory : IFactory {
    public static Phoneline CreateStandardInstance() {
        // phoneline product creation logic goes here
    }
}

public class MobileFactory : IFactory {
    public static Mobile CreateStandardInstance() {
        // mobile product creation logic goes here
    }
}

public class BundleFactory : IAbstractFactory {

    public static Bundle CreateBundle() {
        broadband = BroadbandFactory.CreateStandardInstance();
        phoneline = PhonelineFactory.CreateStandardInstance();
        mobile = MobileFactory.CreateStandardInstance();

        applySomeDiscountOrWhatever(broadband, phoneline, mobile);
    }

    private static void applySomeDiscountOrWhatever(Broadband bb, Phoneline pl, Mobile m) {
        // some logic here
        // maybe manange some variables and invoke some other methods/services/etc.
    }
}

Сподіваюсь, це допомагає.


1
Ні staticв одній із заводських моделей GoF немає методів. Це неправильно.
jaco0646

5

Приклад реального життя (Легко запам’ятати)

Заводська

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

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

Тепер розглянемо той самий приклад дверей. Ви можете піти до столяра, або ви можете піти в магазин пластикових дверей або магазин з ПВХ. Усі вони є дверними фабриками. Виходячи з ситуації, ви вирішуєте, до якої фабрики потрібно підходити. Це як абстрактна фабрика.

Я пояснив тут як заводський метод методу, так і абстрактний заводський шаблон, починаючи з того, щоб не використовувати їх, пояснюючи проблеми, а потім вирішувати проблеми, використовуючи вищезазначені шаблони https://github.com/vikramnagineni/Design-Patterns/tree/master


3

Дамо зрозуміти, що більшу частину часу у виробничому коді ми використовуємо абстрактний заводський зразок, оскільки клас A запрограмований з інтерфейсом B. І A потрібно створити екземпляри B. Отже, A повинен мати заводський об'єкт для отримання екземплярів B Отже, A не залежить від будь-якого конкретного екземпляра В. Сподіваюся, що це допомагає.


3

Зрозумійте відмінності в мотиваціях:

Припустимо, ви будуєте інструмент, у якому є об'єкти та конкретна реалізація взаємозв'язків об'єктів. Оскільки ви передбачаєте зміни в об'єктах, ви створили непрямий характер, поклавши відповідальність за створення варіантів об'єктів іншому об'єкту ( ми називаємо це абстрактним заводом ). Ця абстракція знаходить користь, оскільки ви передбачаєте майбутні розширення, що потребують варіантів цих об'єктів.

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

Простий ( запозичення ідеї у GoF ) - це будь-які програми графічного інтерфейсу, наприклад, віртуальний монітор, який імітує зовнішній вигляд MS або Mac або OS OS OS. Наприклад, коли всі об’єкти віджетів, такі як вікно, кнопка тощо, мають варіант MS, за винятком смуги прокрутки, яка походить від варіанту MAC, призначення інструменту не вдається погано.

Ці вищевикладені випадки є основоположною потребою абстрактних заводських моделей .

З іншого боку, уявіть, що ви пишете фреймворк, щоб багато людей могли будувати різні інструменти ( наприклад, той, що наведений вище ), використовуючи ваш фреймворк. За самою ідеєю рамки вам не потрібно, хоч ви і не могли використовувати конкретні об'єкти у своїй логіці. Ви швидше ставите кілька контрактів високого рівня між різними об'єктами та способами їх взаємодії. Хоча ви ( як розробник фреймворку ) залишаєтесь на дуже абстрактному рівні, кожен розробник цього інструменту змушений слідувати вашим структурам фреймворку. Однак вони ( конструктори інструментів ) мають свободу вирішувати, який об’єкт будувати та як взаємодіють усі створені ними об’єкти. На відміну від попереднього випадку ( абстрактного заводського зразка ), ви ( як творець рамки)) не потрібно в цьому випадку працювати з конкретними предметами; і, скоріше, може залишатися на рівні договору об'єктів. Крім того, на відміну від другої частини попередніх мотивацій, у вас або у виробників інструментів ніколи не виникає ситуацій змішування об'єктів із варіантами. Тут, поки рамковий код залишається на рівні договору, кожен виробник інструментів обмежується ( за характером самого випадку ) використанням власних об'єктів. Створення об'єктів у цьому випадку делегується кожному виконавцеві, а постачальники фреймворків просто забезпечують єдині методи створення та повернення об'єктів. Такі методи неминучі для розробника фреймворку, щоб перейти до свого коду і має спеціальну назву, що називається Фабричний метод ( Factory Method Pattern для базового шаблону ).

Кілька приміток:

  • Якщо ви знайомі з "методом шаблонів", то ви побачите, що заводські методи часто використовуються з шаблонових методів у разі програм, що стосуються будь-якої форми фреймворку. На відміну від цього, шаблонні методи прикладних програм часто є простою реалізацією певного алгоритму та недійсними фабричними методами.
  • Крім того, для повноти думок, використовуючи рамки ( згадані вище ), коли виробник інструментів будує інструмент, всередині кожного фабричного методу, замість створення конкретного об'єкта, він / вона може додатково делегувати відповідальність абстрактному -фабрикальний об'єкт за умови, що інструмент-конструктор передбачив варіації конкретних об'єктів для майбутніх розширень.

Приклад коду:

//Part of framework-code
BoardGame {
    Board createBoard() //factory method. Default implementation can be provided as well
    Piece createPiece() //factory method

    startGame(){        //template method
         Board borad = createBoard()
         Piece piece = createPiece()
         initState(board, piece)
    }
}


//Part of Tool-builder code
Ludo inherits  BoardGame {
     Board createBoard(){ //overriding of factory method
         //Option A: return new LudoBoard() //Lodu knows object creation
         //Option B: return LudoFactory.createBoard() //Lodu asks AbstractFacory
     }
….
}

//Part of Tool-builder code
Chess inherits  BoardGame {
    Board createBoard(){ //overriding of factory method
        //return a Chess board
    }
    ….
}

3
  1. Перше моє запитання - про абстрактну фабрику. Чи є його роль дозволити створювати родини конкретних об'єктів (це може залежати від конкретної фабрики, яку ви використовуєте), а не лише один конкретний об'єкт?

Так. Метою абстрактної фабрики є:

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


  1. Чи повертає абстрактна фабрика лише один дуже великий об'єкт або багато об'єктів залежно від методів, які ви називаєте?

В ідеалі він повинен повертати один об'єкт за методом, який викликає клієнт.

  1. Я розумію, що шаблон заводського методу має інтерфейс Creator, завдяки якому ConcreteCreator несе відповідальність за те, який саме ConcreteProduct створити. Це що означає використання спадщини для обробки екземплярів об'єктів?

Так. Заводський метод використовує успадкування.

  1. Абстрактний заводський зразок делегує відповідальність за інстанціювання об'єкта іншому об'єкту за допомогою композиції? Що це означає?

AbstractFactory визначає FactoryMethod, а ConcreteFactory відповідає за побудову ConcreteProduct. Просто дотримуйтесь прикладу коду в цій статті .

Ви можете знайти більше деталей у пов'язаних публікаціях SE:

У чому полягає основна відмінність фабричних та абстрактних заводських моделей?

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


3

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

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

Діаграма високого рівня фабричної та абстрактної фабрики,

діаграма

Більш детальну інформацію про заводський метод див. У цій статті .

Для отримання додаткової інформації про абстрактний заводський метод див. Цю статтю .


2

Щоб зробити це дуже просто з мінімальним інтерфейсом і будь ласка, фокусуйте "// 1":

class FactoryProgram
    {
        static void Main()
        {
            object myType = Program.MyFactory("byte");
            Console.WriteLine(myType.GetType().Name);

            myType = Program.MyFactory("float"); //3
            Console.WriteLine(myType.GetType().Name);

            Console.ReadKey();
        }

        static object MyFactory(string typeName)
        {
            object desiredType = null; //1
            switch (typeName)
            {
                case "byte": desiredType = new System.Byte(); break; //2
                case "long": desiredType = new System.Int64(); break;
                case "float": desiredType = new System.Single(); break;
                default: throw new System.NotImplementedException();
            }
            return desiredType;
        }
    }

Тут важливі моменти: 1. Фабричні та абстрактніфакторні механізми повинні використовувати успадкування (System.Object-> byte, float ...); тож якщо у вас є спадщина в програмі, то Factory (Фабрика абстрактних не було б там, швидше за все) вже є за проектом 2. Творець (MyFactory) знає про тип бетону, тому повертає об'єкт конкретного типу для виклику (Main); В абстрактному заводському типі повернення буде інтерфейсом.

interface IVehicle { string VehicleName { get; set; } }
interface IVehicleFactory
    {
        IVehicle CreateSingleVehicle(string vehicleType);
    }
class HondaFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports": return new SportsBike();
                case "Regular":return new RegularBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }
class HeroFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports":  return new SportsBike();
                case "Scooty": return new Scooty();
                case "DarkHorse":return new DarkHorseBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }

class RegularBike : IVehicle { public string VehicleName { get { return "Regular Bike- Name"; } set { VehicleName = value; } } }
class SportsBike : IVehicle { public string VehicleName { get { return "Sports Bike- Name"; } set { VehicleName = value; } } }
class RegularScooter : IVehicle { public string VehicleName { get { return "Regular Scooter- Name"; } set { VehicleName = value; } } }
class Scooty : IVehicle { public string VehicleName { get { return "Scooty- Name"; } set { VehicleName = value; } } }
class DarkHorseBike : IVehicle { public string VehicleName { get { return "DarkHorse Bike- Name"; } set { VehicleName = value; } } }

class Program
{
    static void Main(string[] args)
    {
        IVehicleFactory honda = new HondaFactory(); //1
        RegularBike hondaRegularBike = (RegularBike)honda.CreateSingleVehicle("Regular"); //2
        SportsBike hondaSportsBike = (SportsBike)honda.CreateSingleVehicle("Sports");
        Console.WriteLine("******* Honda **********"+hondaRegularBike.VehicleName+ hondaSportsBike.VehicleName);

        IVehicleFactory hero = new HeroFactory();
        DarkHorseBike heroDarkHorseBike = (DarkHorseBike)hero.CreateSingleVehicle("DarkHorse");
        SportsBike heroSportsBike = (SportsBike)hero.CreateSingleVehicle("Sports");
        Scooty heroScooty = (Scooty)hero.CreateSingleVehicle("Scooty");
        Console.WriteLine("******* Hero **********"+heroDarkHorseBike.VehicleName + heroScooty.VehicleName+ heroSportsBike.VehicleName);

        Console.ReadKey();
    }
}

Важливі моменти: 1. Вимога: Honda створює "Регулярні", "Спортивні", але Герой створює "DarkHorse", "Sports" та "Scooty". 2. чому два інтерфейси? Один для типу виробника (IVehicleFactory) та інший для фабрики продукції (IVehicle); інший спосіб зрозуміти 2 інтерфейси - це абстрактні фабрики - це все, що стосується створення пов'язаних об’єктів 2. Улов - діти, які повертаються, і IVehicleFactory, і IVehicle (замість бетону на заводі); тому я отримую батьківську змінну (IVehicle); то я створюю фактичний конкретний тип, викликаючи CreateSingleVehicle, а потім передаваю батьківський об'єкт фактичному дочірньому об'єкту. Що б сталося, якщо я це роблю RegularBike heroRegularBike = (RegularBike)hero.CreateSingleVehicle("Regular");; ви отримаєте ApplicationException, і тому нам потрібен загальний завод абстрактних, який я б пояснив, якщо потрібно.


1

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

Фабрика : Він забезпечує спосіб делегувати логіку інстанції до дочірніх класів. Приклад заводського зразка


0

Я б віддав перевагу абстрактній фабриці над заводським методом у будь-який час. З наведеного вище прикладу Тома Даллінга (велике пояснення btw) ми бачимо, що абстрактна фабрика є більш компонованою в тому, що все, що нам потрібно зробити, - це передати інший завод до конструктора (тут використовується інжекція залежності конструктора). Але Фабричний метод вимагає від нас ввести новий клас (більше речей для управління) та використовувати підкласифікацію. Завжди віддайте перевагу складу над спадщиною.


0

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


Це неправильно. Це загальноприйняте неправильне уявлення про те, що абстрактна фабрика - це не що інше, як фабрика фабрик.
jaco0646

0

Багато з вищезазначених відповідей не дають порівняння коду між абстрактним заводським та заводським способом. Далі йде моя спроба пояснити це через Java. Сподіваюся, це допоможе комусь, хто потребує простого пояснення.

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

        public class Client {
            public static void main(String[] args) {
               ZooFactory zooFactory = new HerbivoreZooFactory();       
               Animal animal1 = zooFactory.animal1();
               Animal animal2 = zooFactory.animal2();
               animal1.sound();
               animal2.sound();

               System.out.println();

               AnimalFactory animalFactory = new CowAnimalFactory();
               Animal animal = animalFactory.createAnimal();
               animal.sound();
            }
        }

        public interface Animal {
            public void sound();
        }

        public class Cow implements Animal {

            @Override
            public void sound() {
                System.out.println("Cow moos");
            }

        }

        public class Deer implements Animal {

            @Override
            public void sound() {
                System.out.println("Deer grunts");
            }

        }

        public class Hyena implements Animal {

            @Override
            public void sound() {
                System.out.println("Hyena.java");
            }

        }

        public class Lion implements Animal {

            @Override
            public void sound() {
                System.out.println("Lion roars");
            }

        }

        public interface ZooFactory {
            Animal animal1();

            Animal animal2();
        }

        public class CarnivoreZooFactory implements ZooFactory {

            @Override
            public Animal animal1() {
                return new Lion();
            }

            @Override
            public Animal animal2() {
                return new Hyena();
            }

        }

        public class HerbivoreZooFactory implements ZooFactory{

            @Override
            public Animal animal1() {
                return new Cow();
            }

            @Override
            public Animal animal2() {
                return new Deer();
            }

        }

        public interface AnimalFactory {
            public Animal createAnimal();
        }

        public class CowAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Cow();
            }

        }

        public class DeerAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Deer();
            }

        }

        public class HyenaAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Hyena();
            }

        }

        public class LionAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Lion();
            }

        }

Це неправильно. Цей код реалізує загальноприйняте неправильне уявлення про те, що абстрактна фабрика - це не що інше, як фабрика фабрик.
jaco0646

1
@ jaco0646 Я вважаю, що у заводській методиці акцент робиться на виведенні лише одного конкретного продукту з FactoryImpl. Враховуючи абстрактний заводський зразок, FactoryImpls несе відповідальність за надання декількох подібних / пов'язаних ConcreteProducts, для яких інтерфейс Factory забезпечує контракт. Так, як ви кажете, ZooFactory - це зовсім не фабрика фабрик, а лише інтерфейс, чиї Impls надають конкретні вироби, які пов'язані між собою. Ви можете виправити моє розуміння, якщо ви не згодні.
Джатін Шашо

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

@ jaco0646 1. Чи означає це, що у наведеному вище прикладі, замість того, щоб використовувати інтерфейси для AnimalFactory та забезпечувати його реалізацію, я мав би використовувати клас і перекрити метод createAnimal () у його підкласах: CowAnimalFactory, LionAnimalFactory тощо. 2. Крім того, які урські думки щодо прикладу, показаного для ZooFactory ??
Джатін Шашо

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