Фабричные классы [закрыто]


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

7 51

7 ответов:

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

вот пример: вы хотите получить доступ к одной из услуг, предоставляемых Google App Engine. Один и тот же код должен работать на обоих среда разработки (из которых есть две версии, master-slave и high-availabilty) и совершенно другая локальная среда разработки. Google не хочет рассказывать вам о внутренней работе своей внутренней инфраструктуры, и вы действительно не хотите знать. Поэтому они предоставляют интерфейсы и фабрики (и несколько реализаций этих интерфейсов для фабрик на выбор, о которых вам даже не нужно знать).

вот настоящая живая фабрика из моей базы кода. Он используется для создания класса sampler, который знает, как выполнять выборку данных из некоторого набора данных (он изначально находится в C#, поэтому извините за любой Java faux-pas)

class SamplerFactory
{
  private static Hashtable<SamplingType, ISampler> samplers;

  static
  {
    samplers = new Hashtable<SamplingType, ISampler>();
    samplers.put(SamplingType.Scalar, new ScalarSampler());
    samplers.put(SamplingType.Vector, new VectorSampler());
    samplers.put(SamplingType.Array, new ArraySampler());
  }

  public static ISampler GetSampler(SamplingType samplingType)
  {
    if (!samplers.containsKey(samplingType))
      throw new IllegalArgumentException("Invalid sampling type or sampler not initialized");
    return samplers.get(samplingType);
  }
}

а вот пример использования:

ISampler sampler = SamplerFactory.GetSampler(SamplingType.Array);
dataSet = sampler.Sample(dataSet);

как вы видите, это не так много кода, и это может быть даже короче и быстрее просто сделать

ArraySampler sampler = new ArraySampler();
dataSet = sampler.Sample(dataSet);

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

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

    void ProcessData(Object dataSet, SamplingType sampling)
    {
      //do something with data
      ISampler sampler = SamplerFactory.GetSampler(sampling);
      dataSet= sampler.Sample(dataSet);
      //do something other with data
    }
    

    вместо более громоздкой конструкции, как это:

    void ProcessData(Object dataSet, SamplingType sampling)
    {
      //do something with data
      ISampler sampler;
      switch (sampling) {
        case SamplingType.Scalar:  
          sampler= new ScalarSampler();
          break;
        case SamplingType.Vector:  
          sampler= new VectorSampler();
          break;
        case SamplingType.Array:
          sampler= new ArraySampler();
          break;
        default:
          throw new IllegalArgumentException("Invalid sampling type");
      }
      dataSet= sampler.Sample(dataSet);
      //do something other with data
    }
    

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

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

    samplers.put(SamplingType.Array, new ArraySampler());
    

    до

    samplers.put(SamplingType.Array, new ScalarSampler());
    

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

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

Это означает, что в качестве разработчика я работаю с известным интерфейсом к экземпляру объекта, но меня не интересует, как работает реализация.

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

Я бы не хотел писать реализации для каждого из этих случаев: P

из эффективной Java-книги Джошуа Блоха, частично переписанной мной:

1) статические методы фабрики ( SFM), в отличие от конструкторов, имеют имена.

public static ComplexNumber one () {
    return new ComplexNumber(1, 0);
}

public static ComplexNumber imgOne () {
    return new ComplexNumber(0, 1);
}

public static ComplexNumber zero () {
    return new ComplexNumber(0, 0);
}

2) не требуется создавать новый объект каждый раз SFM is / вызываются

public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE; 
}

3) SFM может возвращать объект любого подтип возвращаемого типа.

4) SFM уменьшите детализацию создания экземпляров параметризованных типов.

public static <K, V> HashMap<K, V> newInstance() {
    return new HashMap<K, V>();
}

Map<String, List<String>> m = HashMap.newInstance();

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

в этом случае можно создать статические методы фабрики. В Java Boolean класс пример: Boolean.valueOf().

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

вы можете обратиться к Википедия, но основная идея большинства шаблонов проектирования заключается в том, чтобы ввести некоторую абстракцию для достижения лучшей ремонтопригодности и/или повторного использования. Фабричный метод pattern не является исключением, что он делает, чтобы абстрагироваться от сложности создания из кода.

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

например, если не требуется новый экземпляр, статическая фабрика valueOf(boolean) как правило, лучший выбор, чем new Bealean(boolean), ибо это позволяет избежать создания ненужных объектов. Шаблон Заводского метода также известен как Виртуальный Конструктор. Как известно, полиморфизм является одной из ключевых особенностей ООП, но конструктор не может быть полиморфным, этот недостаток может быть преодолен заводским методом pattern.

по сути, создание экземпляра объекта напрямую(обычно через new) едва б реализация, в то время как шаблон Заводского метода защищает a летучиереализация на стабильныйинтерфейс(не ограничиваясь interface в Java), подталкивая логику создания объектов за некоторой абстракцией, чтобы обеспечить более удобный и многоразовый код.

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