Каковы различия между абстрактными фабричными и фабричными шаблонами?

455

Я знаю, что есть много сообщений о различиях между этими двумя моделями, но есть несколько вещей, которые я не могу найти.

Из того, что я читал, я вижу, что шаблон фабричного метода позволяет вам определить, как создать отдельный конкретный продукт, но скрыть реализацию от клиента, поскольку они увидят общий продукт. Мой первый вопрос об абстрактной фабрике. Его роль - позволить вам создавать семейства конкретных объектов (которые могут зависеть от того, какую конкретную фабрику вы используете), а не только один конкретный объект? Абстрактная фабрика возвращает только один очень большой объект или много объектов в зависимости от того, какие методы вы вызываете?

Мои последние два вопроса касаются одной цитаты, которую я не могу полностью понять, которую я видел во многих местах:

Одно из различий между ними заключается в том, что с шаблоном Abstract Factory класс делегирует ответственность за создание экземпляра объекта другому объекту посредством композиции, тогда как шаблон Factory Method использует наследование и опирается на подкласс для обработки требуемого экземпляра объекта.

Насколько я понимаю, шаблон фабричного метода имеет интерфейс Creator, который позволит ConcreteCreator знать, какой экземпляр ConcreteProduct нужно создать. Это то, что это означает, используя наследование для обработки объекта?

Теперь, что касается этой цитаты, как именно шаблон Abstract Factory делегирует ответственность за создание экземпляра объекта другому объекту посредством композиции? Что это значит? Похоже, что шаблон Abstract Factory также использует наследование для выполнения процесса построения в моих глазах, но опять же я все еще изучаю эти шаблоны.

Любая помощь, особенно с последним вопросом, будет принята с благодарностью.

Silverbolt
источник
Просмотр «того, как экземпляр создан» с точки зрения клиента, поможет вам понять цитату.
Картик Бозе
@nawfal, ответы в этой теме ужасны.
jaco0646

Ответы:

494

Разница между двумя

Основное различие между «фабричным методом» и «абстрактной фабрикой» состоит в том, что фабричный метод - это отдельный метод, а абстрактная фабрика - это объект. Я думаю, что многие люди путают эти два термина и начинают использовать их взаимозаменяемо. Я помню, что мне было трудно найти, в чем именно разница, когда я узнал их.

Поскольку фабричный метод является просто методом, он может быть переопределен в подклассе, отсюда и вторая половина вашей цитаты:

... шаблон фабричного метода использует наследование и опирается на подкласс для обработки желаемого экземпляра объекта.

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

Абстрактная фабрика - это объект с несколькими фабричными методами. Глядя на первую половину вашей цитаты:

... с помощью шаблона Abstract Factory класс делегирует ответственность за создание экземпляра объекта другому объекту посредством композиции ...

Они говорят, что есть объект 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
Не уверен, что это правильно. Уверен, что Factory Method - это шаблон проектирования, названный в честь фабричных методов, но включающий структуру классов и наследование. Это не единственный метод.
Авив Кон
2
Поэтому правильно сказать: метод Factory может быть методом во всех обычных классах с различными целями. Но Абстрактная Фабрика - это класс / объект, используемый клиентом, и несет ТОЛЬКО ответственность за создание некоторых продуктов в семье?
Хиеу Нгуен
Является ли использование вами слова «Super» в «SuperFoo» просто для обозначения особого случая Foo, или оно действительно означает «суперкласс»? Как я и предполагал, это должен быть подкласс.
Дахуэй
@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 ( принцип подстановки Лискова ).

jgauffin
источник
3
Зачем нам нужен конкретный продукт?
Эндрю С
60
Потому что никто не хочет вкладывать деньги в идеи.
jgauffin
4
Абстрактная фабрика должна создавать больше, чем просто Button()«семейство связанных продуктов». Например, канонический пример GoF создает ScrollBar()и Window(). Преимущество заключается в том, что абстрактная фабрика может применять общую тему для нескольких продуктов.
jaco0646
Жако прав. Учтите, что обе UML-диаграммы, по сути, одинаковы (за исключением UML «Абстрактной фабрики»). В обоих случаях клиент вызывает фабричный метод для создания одного продукта.
коренастый
1
@AndrewS: чтобы ответить на ваш вопрос. Если нам не нужны разные конкретные продукты (классы) для одной и той же абстракции (интерфейса), нам, скорее всего, нужен шаблон компоновщика, а не шаблон фабрики. (лучше поздно, чем никогда;))
jgauffin
95

Разница между шаблонами проектирования AbstractFactory и Factory заключается в следующем:

  • Фабричный метод используется только для создания одного продукта, но Абстрактная Фабрика предназначена для создания семейств связанных или зависимых продуктов.
  • Шаблон Factory Method предоставляет клиенту метод для создания объекта, тогда как в случае Abstract Factory они предоставляют семейство связанных объектов, которые могут состоять из этих методов Factory.
  • Шаблон Factory Method скрывает построение одного объекта, тогда как Abstract Factory скрывает построение семейства связанных объектов. Абстрактные фабрики обычно реализуются с использованием (набора) фабричных методов.
  • Абстрактный шаблон фабрики использует композицию, чтобы делегировать ответственность за создание объекта другому классу, в то время как шаблон проектирования фабричного метода использует наследование и опирается на производный класс или подкласс для создания объекта.
  • Идея шаблона Factory Method заключается в том, что он учитывает случай, когда клиент не знает, какие конкретные классы ему потребуется создать во время выполнения, но просто хочет получить класс, который будет выполнять работу, пока шаблон Abstract Factory лучше всего использовать, когда ваша система должна создавать несколько семейств продуктов или вы хотите предоставить библиотеку продуктов без раскрытия деталей реализации.

Реализация шаблона фабричного метода: Фабричный метод UML

Реализация абстрактной фабричной модели:

Абстрактная фабрика UML

Вибха Санскритаян
источник
13
Ммм, не уверен насчет абстрактного фабричного примера. Я думаю, что фабрика форм и фабрика цветов должны реализовывать одни и те же методы. Но тогда, если я прав, то образец не имеет смысла.
Хоакин Иурчук
4
Точки пули правильные; однако обе диаграммы совершенно неверны и вводят в заблуждение. Посмотрите диаграмму ниже от @Trying для точной модели Abstract Factory.
jaco0646
1
Я должен согласиться, что 2 диаграммы действительно вводят в заблуждение. Я видел их на сайте tutorialspoint, и, честно говоря, я не на 100% согласен с ними. Хотя описания выглядят хорошо
SoftwareDeveloper
Это очень вводит в заблуждение.
diyoda_
Более 50 голосов и диаграммы очень неправильные. Доказательство того, что вы не можете доверять многим проектным ответам на SO.
Фурманатор
27

Основное различие между Абстрактной Фабрикой и Фабричным Методом состоит в том, что Абстрактная Фабрика реализуется Композицией ; но фабричный метод реализован по наследству .

Да, вы правильно прочитали: главное различие между этими двумя шаблонами - это старая композиция против дебатов о наследовании .

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

Абстрактная Фабрика

  1. Здесь важно понять, что абстрактная фабрика вводится в клиента. Вот почему мы говорим, что Абстрактная Фабрика реализуется Композицией. Часто структура внедрения зависимостей выполняет эту задачу; но структура не требуется для DI.
  2. Вторым критическим моментом является то, что конкретные фабрики здесь не являются реализациями Factory Method! Пример кода для Factory Method показан ниже.
  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(). Вот почему мы говорим, что Factory Method реализуется по наследству.
  2. Второй критический момент - помнить, что шаблон метода фабрики - это не более чем специализация шаблона метода шаблона. Две модели имеют одинаковую структуру. Они отличаются только по назначению. Фабричный метод является креативным (он что-то строит), тогда как шаблонный метод является поведенческим (он что-то вычисляет).
  3. И, наконец, третий момент, на который следует обратить внимание: Creatorкласс (родительский) вызывает свой собственный factoryMethod(). Если мы удалим anOperation()из родительского класса, оставив только один метод, он больше не будет шаблоном Factory Method. Другими словами, фабричный метод не может быть реализован менее чем с двумя методами в родительском классе; и один должен ссылаться на другого.
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 определяет два разных Фабричных паттерна, это не единственные существующие Фабричные паттерны. Они даже не являются наиболее часто используемыми фабричными шаблонами. Известным третьим примером является шаблон статической фабрики Джоша Блоха из Effective Java. Книга Head First Design Patterns включает в себя еще один паттерн, который они называют Simple Factory.

Не попадайтесь в ловушку, предполагая, что каждый шаблон фабрики должен соответствовать одному из GoF.

jaco0646
источник
3
Отличный и очень четкий ответ, основанный на хороших примерах, лучший в этой теме ИМО.
Люк Дуда
Отличное объяснение. +1 для метода Factory должен вызывать его абстрактную точку метода фабрики. С этим пунктом очень ясно, без понимания этого пункта: если у нас есть метод фабрики, не вызываемый им сам, подразумевает, что он будет использоваться другим классом, который будет его составлять, и его подклассы будут внедрены, он превращается в абстрактную фабрику , разница становится менее очевидной, если указать, что абстрактный фабричный метод должен вызываться самой фабрикой, как шаблон шаблонного метода
непонятен
Еще один вопрос-замечание. Должен ли factoryMethod()всегда быть protected метод в шаблоне «Factory Method»? (Думаю да)
Ярослав Федорук
1
@YaroslavFedoruk, книга GoF допускает publicфабричные методы, и метод даже не должен быть abstract; но критическим моментом является то, что метод предназначен для наследования, поэтому он не может (например) быть или staticили final. Я сделал метод protectedи abstractздесь, чтобы подчеркнуть (обязательную) расширяемость.
jaco0646
@ nits.kk, вас может заинтересовать соответствующий ответ .
jaco0646
26

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

Абстрактная фабрика UML

Попытка
источник
10
Вы уже опубликовали тот же ответ здесь . Если вы чувствуете, что этот вопрос похож, пометьте его как дубликат.
Яцк
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 не зависит от какого-либо конкретного случая B. Надеюсь, это поможет.

Адриан Лю
источник
3

Понять разницу в мотивации:

Предположим, вы создаете инструмент, в котором есть объекты, и конкретную реализацию взаимосвязей объектов. Поскольку вы предвидите изменения в объектах, вы создали косвенное направление, возложив ответственность за создание вариантов объектов на другой объект ( мы называем это абстрактной фабрикой ). Эта абстракция находит сильное преимущество, так как вы предвидите будущие расширения, которым нужны варианты этих объектов.

Еще одна довольно интригующая мотивация в этой линии мыслей - это случай, когда каждый из объектов всей группы будет иметь соответствующий вариант. Исходя из некоторых условий, будет использоваться любой из вариантов, и в каждом случае все объекты должны быть одного варианта. Это может быть немного противоречивым для понимания, поскольку мы часто склонны думать, что - пока варианты объекта следуют общему унифицированному контракту ( интерфейс в более широком смысле ), конкретный код реализации никогда не должен нарушаться. Интересным фактом здесь является то, что не всегда это верно, особенно когда ожидаемое поведение не может быть смоделировано программным контрактом.

Простым ( заимствуя идею от GoF ) являются любые приложения с графическим интерфейсом, скажем, виртуальный монитор, который имитирует внешний вид ОС MS, Mac или Fedora. Здесь, например, когда все объекты виджета, такие как окно, кнопка и т. Д., Имеют вариант 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
    }
    ….
}
KGhatak
источник
3
  1. Мой первый вопрос об абстрактной фабрике. Его роль - позволить вам создавать семейства конкретных объектов (которые могут зависеть от того, какую конкретную фабрику вы используете), а не только один конкретный объект?

Да. Целью Абстрактной Фабрики является:

Предоставить интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов.


  1. Абстрактная фабрика возвращает только один очень большой объект или много объектов в зависимости от того, какие методы вы вызываете?

В идеале он должен возвращать один объект на метод, который вызывает клиент.

  1. Насколько я понимаю, шаблон фабричного метода имеет интерфейс Creator, который позволит ConcreteCreator знать, какой экземпляр ConcreteProduct нужно создать. Это то, что это означает, используя наследование для обработки объекта?

Да. Фабричный метод использует наследование.

  1. Абстрактный шаблон Фабрика делегирует ответственность создания объекта другому объекту через композицию? Что это значит?

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

Вы можете найти более подробную информацию в соответствующих сообщениях SE:

В чем принципиальная разница между фабричными и абстрактными фабричными моделями?

Шаблоны проектирования: метод фабрики против фабрики против абстрактной фабрики

Равиндра Бабу
источник
3

Фабричный метод опирается на наследование: создание объекта делегируется подклассам, которые реализуют фабричный метод для создания объектов.

Абстрактная фабрика опирается на композицию объекта: создание объекта осуществляется методами, представленными в интерфейсе фабрики.

Диаграмма высокого уровня фабричной и абстрактной фабричной модели,

диаграмма

Для получения дополнительной информации о методе Factory, обратитесь к этой статье .

Для получения дополнительной информации о методе Abstract factory, обратитесь к этой статье .

user2266614
источник
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. Механизмы Factory & AbstractFactory должны использовать наследование (System.Object-> byte, float ...); так что если у вас есть наследование в программе, то Factory (абстрактный Factory, скорее всего, там не будет), уже существует в проекте 2. Creator (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 создаст "Regular", "Sports", а Hero создаст "DarkHorse", "Sports" и "Scooty". 2. почему два интерфейса? Один для типа производителя (IVehicleFactory) и другой для продукта фабрики (IVehicle); Другой способ понять 2 интерфейса - абстрактная фабрика - все о создании связанных объектов 2. Подвох - возвращение потомков IVehicleFactory и IVehicle (вместо бетона на фабрике); поэтому я получаю родительскую переменную (IVehicle); затем я создаю конкретный конкретный тип, вызывая CreateSingleVehicle и затем приводя родительский объект к фактическому дочернему объекту. Что будет, если я сделаю RegularBike heroRegularBike = (RegularBike)hero.CreateSingleVehicle("Regular");; вы получите ApplicationException, и поэтому нам нужна общая абстрактная фабрика, которую я объясню, если потребуется.

Саурабх
источник
1

Абстрактная фабрика : фабрика заводов; фабрика, которая группирует отдельные, но связанные / зависимые фабрики вместе без указания их конкретных классов. Пример абстрактной фабрики

Фабрика : предоставляет способ делегировать логику реализации дочерним классам. Пример фабричного образца

Атул Джайн
источник
0

Я бы предпочел Абстрактную Фабрику перед Фабричным Методом в любое время. Из приведенного выше примера Тома Даллинга (отличное объяснение) мы можем видеть, что Абстрактная Фабрика является более компонуемой в том, что все, что нам нужно сделать, это передать другую Фабрику в конструктор (здесь используется внедрение зависимости конструктора). Но Factory Method требует от нас ввести новый класс (больше вещей для управления) и использовать подклассы. Всегда предпочитайте композицию наследству.

he9lin
источник
0

позвольте мне сказать это точно. большинство ответов уже объяснены, предоставлены диаграммы и примеры. так что мой ответ будет только один лайнер. мои собственные слова: - «абстрактный шаблон фабрики добавляет на абстрактный слой несколько реализаций метода фабрики. означает, что абстрактная фабрика содержит или объединяет один или несколько шаблонов фабричных методов »

король
источник
Это не правильно. Это слишком распространенное заблуждение, что Абстрактная Фабрика - не более чем фабрика фабрик.
jaco0646
0

Многие из приведенных выше ответов не обеспечивают сравнения кода между шаблоном Abstract Factory и Factory Method. Следующее - моя попытка объяснить это через 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 - это вовсе не фабрика фабрик, а просто интерфейс, с помощью которого вы получаете конкретные продукты, которые связаны друг с другом. Не стесняйтесь исправить мое понимание, если вы не согласны.
Джатин Шашу
В фабричном методе основное внимание уделяется наследованию посредством подклассов, поскольку фабричный метод является специализацией шаблона Template Method. Ответ с наибольшим количеством голосов выше показывает пример достойного кода.
jaco0646
@ jaco0646 1. Означает ли это, что в приведенном выше примере вместо использования интерфейсов для AnimalFactory и предоставления его реализаций я должен был использовать класс и переопределить метод createAnimal () в его подклассах: CowAnimalFactory, LionAnimalFactory и т. д. ?? 2. Кроме того, что вы думаете о примере, показанном для ZooFactory?
Джатин Шашу
На первый вопрос: да. Ко второму я добавил свой собственный ответ в эту ветку, а не продолжать критиковать каждый отдельный ответ.
jaco0646