Что такое статические фабричные методы? - PullRequest
233 голосов
/ 30 мая 2009

Что такое метод "статической фабрики"?

Ответы [ 14 ]

445 голосов
/ 30 мая 2009

Статический шаблон фабричного метода - это способ инкапсуляции создания объекта. Без фабричного метода вы бы просто вызвали класс конструктор напрямую: Foo x = new Foo(). С этим шаблоном вы бы вместо этого вызвали фабричный метод: Foo x = Foo.create(). Конструкторы помечены как частные, поэтому их нельзя вызывать, кроме как изнутри класса, а метод фабрики помечается как static, поэтому его можно вызывать без предварительного наличия объекта.

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

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

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

Coordinate c = Coordinate.createFromCartesian(double x, double y)

и

Coordinate c = Coordinate.createFromPolar(double distance, double angle)

Это также может быть использовано для улучшения читабельности, как отмечает Расмус.

153 голосов
/ 28 марта 2012

Примечание! «Статический фабричный метод равен НЕ так же, как фабричный метод » (c) Effective Java, Joshua Bloch.

Метод фабрики: «Определите интерфейс для создания объекта, но пусть классы, реализующие интерфейс, решат, какой класс создать. Метод Factory позволяет классу отложить создание экземпляров для подклассов» (c) GoF.

"Статический метод фабрики - это просто статический метод, который возвращает экземпляр класса." (в) Эффективная Ява, Джошуа Блох. Обычно этот метод находится внутри определенного класса.

Разница:

Ключевая идея статического фабричного метода - получить контроль над созданием объекта и передать его от конструктора статическому методу. Решение об объекте, который будет создан, похоже на абстрактную фабрику, сделанную вне метода (в общем случае, но не всегда). В то время как ключевая (!) Идея Factory Method - делегировать решение о том, какой экземпляр класса создать внутри Factory Method. Например. Классическая реализация Singleton является частным случаем статического метода фабрики. Пример часто используемых статических фабричных методов:

  • значение
  • getInstance
  • newInstance
112 голосов
/ 30 мая 2009

Мы избегаем предоставления прямого доступа к соединениям с базой данных, поскольку они требуют значительных ресурсов. Поэтому мы используем статический фабричный метод getDbConnection, который создает соединение, если мы находимся ниже предела. В противном случае он пытается создать «резервное» соединение, в случае неудачи с исключением, если оно отсутствует.

public class DbConnection{
   private static final int MAX_CONNS = 100;
   private static int totalConnections = 0;

   private static Set<DbConnection> availableConnections = new HashSet<DbConnection>();

   private DbConnection(){
     // ...
     totalConnections++;
   }

   public static DbConnection getDbConnection(){

     if(totalConnections < MAX_CONNS){
       return new DbConnection();

     }else if(availableConnections.size() > 0){
         DbConnection dbc = availableConnections.iterator().next();
         availableConnections.remove(dbc);
         return dbc;

     }else {
         throw new NoDbConnections();
     }
   }

   public static void returnDbConnection(DbConnection dbc){
     availableConnections.add(dbc);
     //...
   }
}
67 голосов
/ 30 мая 2009

Читаемость может быть улучшена статическими фабричными методами:

Сравнить

public class Foo{
  public Foo(boolean withBar){
    //...
  }
}

//...

// What exactly does this mean?
Foo foo = new Foo(true);
// You have to lookup the documentation to be sure.
// Even if you remember that the boolean has something to do with a Bar
// you might not remember whether it specified withBar or withoutBar.

до

public class Foo{
  public static Foo createWithBar(){
    //...
  }

  public static Foo createWithoutBar(){
    //...
  }
}

// ...

// This is much easier to read!
Foo foo = Foo.createWithBar();
20 голосов
/ 30 мая 2009
  • имеют имена, в отличие от конструкторов, которые могут уточнить код.
  • не нужно создавать новый объект при каждом вызове - объекты при необходимости может быть кэширован и использован повторно.
  • может возвращать подтип их типа возврата - в частности, может вернуть объект, класс реализации которого неизвестен вызывающей стороне. Это очень ценная и широко используемая функция во многих средах которые используют интерфейсы в качестве возвращаемого типа статических фабричных методов.

от http://www.javapractices.com/topic/TopicAction.do?Id=21

18 голосов
/ 30 мая 2009

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

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

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

10 голосов
/ 05 декабря 2012

Если конструктор класса является закрытым, вы не можете создать объект для класса извне.

class Test{
 int x, y;
 private Test(){
  .......
  .......
  }
}

Мы не можем создать объект для вышеуказанного класса извне. Таким образом, вы не можете получить доступ к x, y извне класса. Тогда какая польза от этого класса?
Вот ответ: FACTORY метод.
Добавьте метод ниже в классе выше

public static Test getObject(){
  return new Test();
}

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

Test t = Test.getObject();

Следовательно, статический метод, который возвращает объект класса путем выполнения его частного конструктора, называется FACTORY метод
.

8 голосов
/ 22 сентября 2013

Я думал, что добавлю немного света в этот пост о том, что я знаю. Мы широко использовали эту технику в нашем recent android project. Вместо creating objects using new operator вы также можете использовать static method для создания экземпляра класса. Список кодов:

//instantiating a class using constructor
Vinoth vin = new Vinoth(); 

//instantiating the class using static method
Class Vinoth{
  private Vinoth(){
  }
  // factory method to instantiate the class
  public static Vinoth getInstance(){
    if(someCondition)
        return new Vinoth();
  }
}

Статические методы поддерживают создание условных объектов : Каждый раз, когда вы вызываете конструктор, объект создается, но вы, возможно, этого не хотите. Предположим, вы хотите проверить какое-то условие только тогда, когда захотите создать новый объект. Вы не будете создавать новый экземпляр Vinoth каждый раз, если ваше условие не будет выполнено.

Другой пример взят из Effective Java .

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

Этот метод переводит логическое примитивное значение в ссылку на логический объект. Метод Boolean.valueOf(boolean) иллюстрирует нас, он никогда не создает объект. Способность static factory methods возвращать один и тот же объект из повторяющегося invocations позволяет классам сохранять строгий контроль над тем, какие экземпляры существуют в любое время.

Static factory methods заключается в том, что, в отличие от constructors, они могут возвращать object любого subtype своего типа возврата. Одним из применений этой гибкости является то, что API может возвращать объекты, не делая их классы общедоступными. Сокрытие классов реализации таким способом приводит к очень компактному API.

Calendar.getInstance () является отличным примером для вышеупомянутого, он создает в зависимости от локали BuddhistCalendar, JapaneseImperialCalendar или по умолчанию один Georgian.

Другой пример, о котором я мог бы подумать, это Singleton pattern, где вы делаете свои конструкторы приватными, создаете собственный метод getInstance, где вы убедитесь, что всегда доступен только один экземпляр.

public class Singleton{
    //initailzed during class loading
    private static final Singleton INSTANCE = new Singleton();

    //to prevent creating another instance of Singleton
    private Singleton(){}

    public static Singleton getSingleton(){
        return INSTANCE;
    }
}
4 голосов
/ 30 мая 2009

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

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

3 голосов
/ 04 октября 2015

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

...