Реалистичный вариант использования статического заводского метода? - PullRequest
13 голосов
/ 16 ноября 2010

Я знаком с идеей и преимуществами статического метода фабрики, как описано в Effective Java Джошуа Блоха:

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

Теперь я пытаюсь объяснить статическиефабричные методы для тех, кто изучает принципы Java и OO.Она лучше всего учится на конкретных сценариях, а не на абстракциях.Если она сможет увидеть шаблон на работе, решив какую-то проблему, она его получит.Но ей труднее читать абстрактный список характеристик, подобных приведенным выше, чтобы понять, как применять шаблон.

Можете ли вы помочь мне привести реалистичный пример использования статического метода фабрики, который дает свои преимуществаясно, но что все еще достаточно просто, чтобы показать кого-то во вводном классе Java?

Этот человек имеет опыт программирования на PL / SQL, но никогда не удосужился изучить шаблоны ООП.

Ответы [ 6 ]

15 голосов
/ 16 ноября 2010

Используйте javax.swing.BorderFactory в качестве примера всех трех точек.

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

  • Существует несколько статических методов с разными именами, например createEmptyBorder() и createEtchedBorder().
  • Эти методы будут возвращать ранее созданные объекты, когда это возможно. Очень часто одна и та же граница будет использоваться во всем приложении.
  • Border сам по себе является интерфейсом, поэтому все объекты, созданные с помощью этой фабрики, на самом деле являются классами, реализующими этот интерфейс.
4 голосов
/ 16 ноября 2010

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

  • Поскольку ImmutableList не предоставляет никаких конструкторов public или protected, он может быть разделен на подклассы в пакете, не позволяя пользователям создавать его подклассы (и потенциально нарушать его гарантию неизменности).
  • Учитывая, что все его фабричные методы способны возвращать специализированные подклассы этого, не раскрывая их типы.
  • Его фабричный метод ImmutableList.of() возвращает одноэлементный экземпляр EmptyImmutableList. Это демонстрирует, как статическому методу фабрики не нужно создавать новый экземпляр, если это не нужно.
  • Его метод ImmutableList.of(E) возвращает экземпляр SingletonImmutableList, который оптимизирован, поскольку он будет содержать только 1 элемент.
  • Большинство других фабричных методов возвращают RegularImmutableList.
  • Его copyOf(Collection) статический метод фабрики также не всегда должен создавать новый экземпляр ... если заданный Collection сам является ImmutableList, он может просто вернуть это!
4 голосов
/ 16 ноября 2010

Пример вашего второго пункта в учебнике: Integer.valueOf(int) (аналогично Boolean, Short, Long, Byte).Для значений параметров от -128 до 127 этот метод возвращает кэшированный экземпляр вместо создания нового Integer.Это делает (авто) упаковку / распаковку намного более производительным для типичных значений.

Вы не можете сделать это с new Integer(), поскольку JLS требует, чтобы new создавал новый экземпляр каждыйвремя это называется.

3 голосов
/ 16 ноября 2010

Не будет ли Calendar.getInstance() хорошим примером?В зависимости от локали он создает буддистский календарь, японский императорский календарь или по умолчанию григорианский календарь.

0 голосов
/ 16 ноября 2010

Простой случай. Предположим, у вас есть класс, который работает с каким-то принтером, но ему все равно, epson, canon или что-то еще. Итак, вы просто создаете интерфейс Printer, создаете несколько его реализаций и создаете класс, у которого есть только один метод: createPrinter.

Итак, код будет простым:

   public interface Printer {
       print();
    }

    class CanonPrinter implements Printer {
       print() {
    // ...
       }
    }


    public PrinterFactory {

    Printer createPrinter() {
   if (... ) {
      return new CanonPrinter();
   } else {
      return new EpsonPrinter();
   }
}
}

код клиента:

Printer printer = PrinterFactory.createPrinter();
printer.print();

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

0 голосов
/ 16 ноября 2010

Вот один, который я должен был сделать некоторое время назад.На собеседовании меня попросили запрограммировать колоду карт, где их можно перетасовать.Действительно простая проблема.Я создал:

Card:
  suit
  rank

Deck:
  card[]

Я думаю, что отличительным фактором было то, что всегда может быть только 52 карты.Поэтому я сделал конструктор для Card () закрытым и вместо этого создал статическую фабричную стоимость (масти, ранга). Это позволило мне кэшировать 52 карты и сделать их неизменяемыми.Он преподал много важных базовых уроков в этих книгах.

  1. неизменяемый
  2. контролирует создание объекта
  3. статические методы
  4. , возможно, создает подкласс и возвращает карту из другого источника.(Я этого не делал)

Это похоже на Boolean и Byte, за исключением того, что я использовал общий пример домашней работы, чтобы показать, почему важно контролировать экземпляры.Я также создал вспомогательную функцию для deck под названием newDeck (), потому что я хотел показать экземпляр, в котором конструктору может не потребоваться быть закрытым, но было бы неплохо иметь вспомогательную статическую фабрику.

Надеюсьпомогает!

...