2009-07-22 4 views
3

В абстрактной фабрике вы объявляете тип, который отвечает за создание объектов.Где создать AbstractFactory

Это позволит предотвратить требующий выключателя как это:

if(type == ONE) { 
    doOne(); 
    } else if(type == TWO) { 
    doTwo(); 
    } etc. 

Или же:

switch(type) { 
    case ONE: doOne(); break; 
    case TWO: doTwo(); break; 
    etc.... 
    } 

В это:

MyAbstractFactory factoryInstance = ... ? 

    SomeObject object = factoryInstance.createObject(); 

    object.doX(); 

Как я понимаю AbstractFactory создаст правильный объект который, в свою очередь, выполнит полиморфно правильное поведение.

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

object.doY(); 

    object.doZ(); 

Добавление нового типа так же просто, как создать новую бетонную фабрику.

Все это ясно для меня. Но ...

Где и как создается конкретная фабрика (в общих чертах) в первую очередь?

Я всегда использовал одну единственную точку (обычно в методе main() или в методе Configuration.init()), который, в свою очередь, имеет конструкцию if/else | switch, которая неизбежна, но по крайней мере она используется только один раз.

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

:)

+0

Это спорный вопрос? Похоже, вы уже ответили на него в своем втором-последнем абзаце! –

+0

Почему бы вам просто не использовать Spring и фасонные фабрики, которые он предоставляет? –

+0

Если else/switch не является неизбежным, но вполне может быть реализацией, которая будет работать лучше всего. (вам в основном нужна таблица перехода, и если вы включите int, то вы получите из блока переключателей, но вы можете использовать массив создателей и некоторый индекс (нужный вам тип) –

ответ

0

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

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

Другой альтернативой оператору if является карта (словарь в C#, я полагаю), которая имеет поиск по типу либо объекту-строителю, либо самому объекту (если он является неизменным), либо экземпляру объект, который может копировать себя.

Другой вариант - сделать тип Enum, который имеет метод, который может создать экземпляр нужного объекта.

1

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

Например позволяет сказать, что вы производитель автомобилей/грузовик, у вас есть такие предметы, как CarSeats, CarStereo и т.д., и у вас также есть TruckSeats, TruckStereo, все они реализуют некоторые интерфейс тот общий для все они говорят IVehicleItem. На данный момент у вас могут быть 2 фабрики TruckFactory и CarFactory, которые оба выполняют абстрактный завод, скажем VehicleFactory. Теперь вы можете сделать что-то подобное.

VehicleFactory carFactory = new CarFactory(); 
IVehicle car = new Car(carFactory); 

VehicleFactory truckFactory = new TruckFactory(); 
IVehicle truck = new Truck(truckFactory); 

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

Редактировать добавить: Я думаю, что путаница приходит с людьми, непонимающими, что такое абстрактная фабрика. Возможно, это относится к моему «downvote». Abstract Factory Pattern отличается от Factory Method Pattern.

Wiki - абстрактный шаблон фабрики представляет собой сложный шаблон , включающий использование шаблона фабрики и шаблона интерфейса.

Вы упомянули, что не Wiki или GoF..etc показать, как создать экземпляр конкретного класса. Это неправильно, если вы смотрите через Википедии статью для Factory Method шаблон вы увидите этот небольшой отрывок

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

Если вы читали статью Википедии для Abstract Factory Pattern, вы увидите этот небольшой фрагмент кода.

public static GUIFactory createOsSpecificFactory() { 
     int sys = readFromConfigFile("OS_TYPE"); 
     if (sys == 0) { 
      return new WinFactory(); 
     } else { 
      return new OSXFactory(); 
     } 
    } 

Суть в том, что нет «правильного» способа. Вы создаете конкретные классы, основываясь на том, что вы пытаетесь сделать в приложении. Конечно, утверждения «если» или «переключатель» можно избежать. Но лично я не вижу ничего плохого в их использовании.

+0

Ну, это моя точка зрения. Я не могу скомпоновать новый CarFactory() или я могу? Это мой вопрос. Правильный путь? Hardcode - реализация и изменение его на дистрибутиве? Может быть, это возможность? Что относительно тех мест, где должно быть динамически загружено? – OscarRyz

+0

Что такое downvote для? –

1

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

Ваш клиентский код может выглядеть следующим образом:

FactoryService service = FactoryService.instance(); 
MyAbstractFactory factory = service.getFactory(); 
SomeObject obj = factory.createObject(); 

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

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

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

+0

FactoryService, в свою очередь, AbtractFacto он сам. И вопрос повторяется? Когда нужно создать экземпляр? Вторая часть - это один выбор, у которого инжектор зависимости читает конфигурационный файл. :) – OscarRyz

+0

Не обязательно - FactoryService - это конкретная реализация (singleton, в случае, показанном выше), которая скрывает детали создания конкретного экземпляра абстрактной фабрики. Правда, FactoryService - это завод, но не AbstractFactory. – Armadillo

0

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

Первый случай, когда для запуска объекта будет использоваться только один конкретный класс. Каноническим примером этого является код доступа к базе данных: вы не собираетесь получать доступ к базе данных на SQL Server, а затем внезапно переключаетесь на Oracle. Конкретный класс устойчив. Для этого я использую модель Provider: определите класс ProviderBase, класс ProviderCollection и т. Д.

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

0

Использование некоторых рамок IoC в этом примере является самым гибким решением - весна была рекомендована в более ранних ответах, Google Guice - еще один отличный выбор, с которого очень легко начать.

Однако, если требуется чистое Java-решение, перечисления работают действительно замечательно. Pls рассмотрим следующий пример:

enum FactoryConfig { 
    CONFIG_1 { 
    IFactory instantiate() { 
     return ... 
    } 
    }, 
    CONFIG_2 { 
    IFactory instantiate() { 
     return ... 
    } 
    }, 
    CONFIG_3 { 
    IFactory instantiate() { 
     return ... 
    } 
    }; 

    abstract IFactory instantiate(); 
} 
... 
// and its usage.. 

IFactory factory = FactoryConfig.CONFIG_3.instantiate(); 

Подробнее о подобном использовании перечислений можно найти, например, here и here.

+0

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

Смежные вопросы