Каковы различия между абстрактными фабричными и фабричными шаблонами? - PullRequest
394 голосов
/ 21 апреля 2011

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

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

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

Одно из различий заключается в том, что с шаблоном Абстрактная фабрика, класс делегирует ответственность создание объекта для другого объекта через композицию, тогда как Фабрика Шаблон метода использует наследование и опирается на подкласс для обработки создание нужного объекта.

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

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

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

Ответы [ 16 ]

430 голосов
/ 21 апреля 2011

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

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

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

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

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

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

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

Они говорят, что есть объект А, который хочет создать объект 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
113 голосов
/ 21 апреля 2011

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

enter image description here

Фабричный метод - это простой метод, используемый для создания объектов.в классе.Обычно он добавляется в сводный корень (класс Order имеет метод с именем CreateOrderLine)

enter image description here

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

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

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 interface.

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

Сводка

Разница в том, что Назначение класса, содержащего фабричный метод , состоит не в создании объектов , а в абстрактных фабричных шо.Можно использовать только для создания объектов.

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

89 голосов
/ 28 октября 2013

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

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

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

Реализация шаблона AbstractFactory:

Abstract Factory UML

22 голосов
/ 18 декабря 2013

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

Abstract Factory UML

14 голосов
/ 10 июня 2018

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

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

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

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

  1. Здесь важно понять, что абстрактная фабрика вводится в клиент.Вот почему мы говорим, что Абстрактная Фабрика реализуется Композицией.Часто платформа внедрения зависимостей выполняет эту задачу;но для DI не требуется каркас.
  2. Вторым критическим моментом является то, что конкретные фабрики здесь не являются реализациями метода фабрики!Пример кода для 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().Вот почему мы говорим, что Фабричный метод реализуется с помощью Inheritance.
  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.

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

10 голосов
/ 01 октября 2016

Рассмотрим этот пример для простоты понимания.

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

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

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

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

В этом случае 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.
    }
}

Надеюсь, это поможет.

3 голосов
/ 22 сентября 2016

Поймите различия в мотивациях:

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

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

Простым ( заимствованием идеи от GoF ) является любое приложение с графическим интерфейсом, скажем, виртуальный монитор, имитирующий внешний вид ОС MS, Mac или Fedora.Здесь, например, когда все объекты виджета, такие как окно, кнопка и т. Д., Имеют вариант MS, за исключением полосы прокрутки, которая получена из варианта MAC, назначение инструмента не удается.

Эти вышеупомянутые случаи формируют фундаментальную потребность Абстрактная модель фабрики .

С другой стороны, представьте, что вы пишете фреймворк, чтобы многие люди могли создавать различные инструменты (, например, как в приведенных выше примерах ), используя ваш фреймворк.По самой идее фреймворка вам не нужно, хотя вы не можете использовать конкретные объекты в своей логике.Вы скорее заключаете какие-то контракты высокого уровня между различными объектами и тем, как они взаимодействуют.Пока вы ( как разработчик фреймворка ) остаетесь на очень абстрактном уровне, каждый создатель инструмента вынужден следовать вашим фреймворк-конструкциям.Тем не менее, они ( строители инструментов ) имеют свободу выбора, какой объект будет построен и как все объекты, которые они создают, будут взаимодействовать.В отличие от предыдущего случая ( для Abstract Factory Pattern ), вам ( как создателю фреймворка ) в этом случае не нужно работать с конкретными объектами;и скорее может остаться на уровне контракта объектов.Кроме того, в отличие от второй части предыдущих мотиваций, у вас или у создателей инструментов никогда не бывает ситуаций смешивания объектов из вариантов.Здесь, пока код фреймворка остается на уровне контракта, каждый производитель инструментов ограничен ( по природе самого случая ) использованием своих собственных объектов.Создание объектов в этом случае делегируется каждому реализатору, а поставщики фреймворка просто предоставляют единые методы для создания и возврата объектов.Такие методы неизбежны для разработчика инфраструктуры для продолжения работы со своим кодом и имеют специальное имя, называемое Factory method ( 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 голосов
/ 15 мая 2016
  1. Мой первый вопрос об абстрактной фабрике. Его роль - позволить вам создавать семейства конкретных объектов (которые могут зависеть от того, какую конкретную фабрику вы используете), а не только один конкретный объект?

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

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


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

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

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

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

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

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

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

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

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

3 голосов
/ 16 июля 2015

Давайте поясним, что большую часть времени в производственном коде мы используем абстрактный шаблон фабрики, потому что класс A запрограммирован с интерфейсом B. И A должен создавать экземпляры B. Поэтому A должен иметь объект фабрики, чтобы произвестиэкземпляры B. Таким образом, A не зависит ни от какого конкретного экземпляра B. Надеюсь, это поможет.

2 голосов
/ 07 сентября 2017

Чтобы сделать это очень просто с минимальным интерфейсом и, пожалуйста, сфокусируйте "// 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, и поэтому нам нужна общая абстрактная фабрика, которую я объясню, если потребуется. Надеюсь, что это поможет от начинающих до промежуточной аудитории.

...