Это шаблон создания фабричного метода? - PullRequest
43 голосов
/ 30 апреля 2009

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

public static class ScheduleTypeFactory
{
    public static IScheduleItem GetScheduleItem(ScheduleTypeEnum scheduleType)
    {
        IScheduleItem scheduleItem = null;

        switch (scheduleType)
        {
            case ScheduleTypeEnum.CableOnDemandScheduleTypeID:
                {
                    scheduleItem = new VODScheduleItem();
                    break;
                }
            case ScheduleTypeEnum.BroadbandScheduleTypeID:
                {
                    scheduleItem = new VODScheduleItem();
                    break;
                }
            case ScheduleTypeEnum.LinearCableScheduleTypeID:
                {
                    scheduleItem = new LinearScheduleItem();
                    break;
                }
            case ScheduleTypeEnum.MobileLinearScheduleTypeID:
                {
                    scheduleItem = new LinearScheduleItem();
                    break;
                }
        }

        return scheduleItem;
    }
}

не является шаблоном создания фабричного метода моим "техническим" лидерством, не говоря мне почему или не давая мне ее интерпретацию. Я любезно попросил объяснений, и она сказала мне, что у нее нет времени. Мне сказали просто переименовать его. Если я ошибаюсь, то, без сомнения, я признаю, что неправильно это реализовал годами. Это то, как ВЫ реализуете шаблон создания фабричного метода? Заранее спасибо.

Ответы [ 20 ]

31 голосов
/ 01 мая 2009

Я бы согласился назвать метод «Фабричным методом», хотя дизайн не является строго «Фабричным методом».
Вот ключевой момент (из Википедии):

... Метод Factory позволяет классу откладывать создание экземпляров для подклассов. "

Поскольку ваш класс статический, а метод статический (следовательно, не виртуальный), отсрочка невозможна.

Концептуально, обратите внимание также, что эта реализация, хотя и обеспечивает инкапсуляцию, не разъединяет / не задерживает какое-либо решение.

Сказав это, в той же статье в Википедии эта схема представляется как вариант"Фабричного шаблона метода".

Краткое изложение резюме: По моему мнению, этот фрагмент не является правильной реализацией "шаблона проектирования OO фабричного метода", поскольку он не удовлетворяет "экземпляру класса, откладывающему подклассы". Хотя лично я бы свободно называл это решение «фабричным методом».

Чтобы сделать его реальным фабричным шаблоном метода, необходимо разрешить переопределение метода подклассами. То есть фабричный класс (ScheduleTypeFactory) должен быть расширяемым (то есть нестатичным), а GetScheduleItem должен быть виртуальным.

29 голосов
/ 30 апреля 2009

Уверен, выглядит для меня как заводская модель. Я не вижу ничего плохого в вашей реализации.

С Шаблон фабричного метода :

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

Это именно то, что вы делаете.

В качестве дополнительного примечания: хорошее эмпирическое правило заключается в том, что всякий раз, когда кто-то говорит вам что-то и не может или не желает предоставить обоснование для своего заявления, есть большая вероятность того, что он вообще не сможет сделать заявление. *

14 голосов
/ 30 апреля 2009

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

default:
  throw new InvalidOperationException("Invalid Enum Value");
12 голосов
/ 14 сентября 2009

Ваш фрагмент кода - это то, что в Head First Design Patterns называется "Простая фабрика" (стр. 117).
Основным отличием от Factory Method Pattern является ConcreteCreator (сравните диаграмму в верхнем правом углу), который является простым классом в вашем случае.
В «реальном шаблоне» фабричный класс является абстрактным с абстрактным фабричным классом. Итак, есть еще один уровень абстракции. Однако для многих случаев достаточно вашей Simple Factory .

Простая фабрика Простая фабрика http://yuml.me/7221a4c9 Шаблон фабричного метода Шаблон фабричного метода http://yuml.me/3d22eb4e

8 голосов
/ 30 апреля 2009

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

8 голосов
/ 07 декабря 2009

Ваш вывод верен (извините за форматирование, но этот ответ нужен, чтобы его можно было увидеть между основной строкой, в которой указывается, что лидерство - идиот): ни книга GOF ни Head First это фабричный метод.

GoF:

«Определите интерфейс для создания объект, но пусть подклассы решают какой класс для создания экземпляра. завод Метод позволяет отложить класс создание экземпляров для подклассов. ”

В вашем примере это не подкласс, который решает .

Вы неправильно это реализовали все эти годы? Нет, вы просто не реализовали фабричный шаблон, но то, что иногда называют «простым фабричным шаблоном», который, вероятно, отлично справился с работой.

5 голосов
/ 01 мая 2009

Я удивлен, что многие говорят, что это заводская модель. (Вероятно, я думаю об этом неправильно, поэтому, пожалуйста, дайте мне знать.)

Мне кажется, что у вас есть только часть дизайна. Если вы вызываете его от своего клиента, это называется «простой» фабрикой, но на самом деле это не считается шаблоном проектирования. (Не поймите меня неправильно, я делаю это все время).

В шаблоне проектирования фабрики будет указано, что ваша фабрика наследует / реализует абстрактный интерфейс фабрики / фабрики.

Затем в вашем классе, который должен использовать фабрику (клиент), вы устанавливаете тип фабрики как абстрактный / интерфейс, создавая конкретную фабрику: т.е. -> IFactory factory = new ConcreteFactory ();

Бетонная фабрика создаст ваш IScheduleItem (оставляя его фабрике для создания конкретного типа).

В конце концов, я думаю, что все дело в слабой связи. Хотя «простая» фабрика слабо связывает конструкцию продукта с клиентом, она не отделяет фабрику. Фабричный образец также разъединяет фабричный.

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

5 голосов
/ 30 апреля 2009

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

4 голосов
/ 30 апреля 2009

Ну, Википедия говорит это фабричный метод:

public class ImageReaderFactory 
{
    public static ImageReader getImageReader( InputStream is ) 
    {
        int imageType = figureOutImageType( is );

        switch( imageType ) 
        {
            case ImageReaderFactory.GIF:
                return new GifReader( is );
            case ImageReaderFactory.JPEG:
                return new JpegReader( is );
            // etc.
        }
    }
}
4 голосов
/ 30 апреля 2009

Это шаблон Factory, но он не обязательно является наиболее приемлемым вариантом. Более обслуживаемый вариант будет поддерживать какую-то глобальную карту между ScheduleTypeEnum значениями и фактическими конкретными подтипами IScheduleItem - таким образом, вы можете заменить оператор switch поиском карты.

Почему он более удобен в обслуживании? Поскольку авторы подкласса могут добавлять пары на карту на сайте, где они получают класс , а не в самой фабричной функции GetScheduleItem(). Следовательно, последний никогда не нуждается в обновлении; это постоянно актуально.

В C ++ вы можете сделать это, используя глобальный std::map - для каждого конкретного подкласса автор подкласса добавляет фиктивную глобальную переменную, которая фактически просто регистрирует класс (путем добавления в карту) в своем конструкторе, который работает во время запуска программы. Я уверен, что в C # есть удобный способ сделать то же самое.

(у гуру C ++ у Херба Саттера есть занимательное описание здесь , но оно довольно C ++ - тяжелое.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...