Пример шаблона Builder в Java API? - PullRequest
13 голосов
/ 30 января 2010

Joshua Bloch's Effective Java описывает шаблон построителя, который можно использовать для построения объектов с несколькими необязательными параметрами. Соглашение об именах, которое он предлагает для функций Builder, которое «имитирует именованные необязательные параметры, как это найдено в Ada и Python», похоже, не соответствует стандартному соглашению об именах Java. Java-функции имеют тенденцию полагаться на наличие глагола для запуска функции, а затем на основе существительной фразы для описания того, что она делает. Класс Builder имеет только имя переменной, которая должна быть определена этой функцией.

Существуют ли какие-либо API в стандартных библиотеках Java, которые используют шаблон Builder? Я хочу сравнить предложения в книге с реальной реализацией в базовом наборе библиотек Java, прежде чем приступить к ее использованию.

Ответы [ 7 ]

17 голосов
/ 30 января 2010

Я не уверен насчет ядра JDK, но хорошие примеры можно найти в Guava . MapMaker - это, пожалуй, лучший пример, который я могу придумать с моей головы. Например, из документов:

ConcurrentMap<Key, Graph> graphs = new MapMaker()
    .concurrencyLevel(32)
    .softKeys()
    .weakValues()
    .expiration(30, TimeUnit.MINUTES)
    .makeComputingMap(
        new Function<Key, Graph>() {
          public Graph apply(Key key) {
            return createExpensiveGraph(key);
          }
        });

Да, подобные вещи могут идти вразрез с "стандартным" именованием Java, но они также могут быть очень удобочитаемыми.

Для ситуаций, когда вы возвращаете не «this», а новый объект (обычно с неизменяемыми типами), мне нравится префикс «with» - Joda Time широко использует этот шаблон. Это не шаблон строителя, а альтернативная и связанная форма построения.

5 голосов
/ 10 июня 2016

Класс Locale имеет пример шаблона Builder. https://docs.oracle.com/javase/7/docs/api/java/util/Locale.Builder.html

Использование:

Locale locale = new Builder().setLanguage("sr").setScript("Latn").setRegion("RS").build();
4 голосов
/ 23 марта 2011

Единственный конструктор, наиболее точный в книге «Эффективная Java», - это StringBuilder. Единственное отличие, которое я вижу из примера, состоит в том, что этот построитель не является внутренним классом String.

Все методы возвращают объект компоновщика в цепочку. а метод toString () является методом build ().

2 голосов
/ 17 ноября 2017

Довольно хороший пример из Java 8 Core API - Calendar, например, вы можете использовать:

Calendar cal = new Calendar.Builder().setCalendarType("iso8601")
                        .setWeekDate(2013, 1, MONDAY).build();

Еще один хороший пример из Java 7 - Locale, используйте:

Locale aLocale = new Builder().setLanguage("sr").setScript("Latn").setRegion("RS").build();

Шаблон строителя наиболее полезен в контексте неизменяемых объектов. Интересно, что в Java есть много изменяемых компоновщиков, наиболее распространенным из которых является StringBuilder. Изменяемые компоновщики из Java 8:

  • Stream.Builder
  • IntStream.Builder
  • LongStream.Builder
  • DoubleStream.Builder
2 голосов
/ 03 января 2012

SAXParser кажется хорошим примером:

  • SAXParser - Директор
  • ContentHandler - Строитель

Типичное использование SAXParser идентично с Builder:

// Create Director
SAXParser parser = new org.apache.xerces.parsers.SAXParser();  
// Create Concrete Builder (our own class)
IdentingContentHandler handler = new IndentingContentHandler();
// Set Buidler to Director
parser.setContentHandler(handler);
// Build
parser.parse(new InputSource(new FileReader(fileName));
// Get indented XML as String from handler
String identedXML = handler.getResult();
1 голос
/ 04 февраля 2010

ProcessBuilder является в значительной степени экземпляром шаблона построителя, но не совсем использует соглашения об именах java.

 ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
 Map env = pb.environment();
 env.put("VAR1", "myValue");
 env.remove("OTHERVAR");
 env.put("VAR2", env.get("VAR1") + "suffix");
 pb.directory(new File("myDir"));
 Process p = pb.start();

В пакете SQL PreparedStatement можно рассматривать как экземпляр шаблона построителя:

 PreparedStatement stmt = conn.prepareStatement(getSql());
 stmt.setString(1, ...);
 stmt.setString(2, ...);
 ResultSet rs = stmt.executeQuery();
 ...
 stmt.setString(2, ...);
 rs = stmt.executeQuery();
 ...
0 голосов
/ 30 января 2010

Он определен (не реализован) только в стандартной библиотеке, однако объекты JDBC DataSource напоминают мне шаблон компоновщика. Вы создаете объект DataSource, затем задаете ряд свойств и затем устанавливаете соединение.

Вот пример кода ...

DataSource ds = (DataSource)ctx.lookup("jdbc/AcmeDB");
ds.setServerName("my_database_server");
ds.setDescription("the data source for inventory and personnel");
Connection con = ds.getConnection("genius", "abracadabra");
...