Подтвердить что ты не робот

Factory классы

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

4b9b3361

Ответ 1

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

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

Ответ 2

Вот реальная живая factory из моей базы кода. Он использовался для создания класса сэмплеров, который знает, как отбирать данные из некоторого набора данных (изначально он был на С#, поэтому извините любой 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);

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

  • Во-первых, это простота и удобство обслуживания кода. Скажем, что в вызывающем коде параметр 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. И этот factory имеет только три варианта, представьте себе factory с 20 реализациями.

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

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

    к

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

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

Ответ 3

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

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

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

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

Ответ 4

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

1) Статические методы factory (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

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();

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

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

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

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

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