Пример шаблона Builder в Java API?


Джошуа Блохаэффективная Java описывает шаблон компоновщика, который может быть использован для построения объектов с несколькими опционально настраиваемыми параметрами. Соглашение об именовании, которое он предлагает для функций Builder, которое "имитирует именованные необязательные параметры, найденные в Ada и Python", похоже, не соответствует стандартному соглашению об именовании Java. Функции Java, как правило, полагаются на наличие глагола, чтобы запустить функцию, а затем фразу на основе существительного, чтобы описать, что она делает. То Класс Builder имеет только имя переменной, которая должна быть определена этой функцией.

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

7 12

7 ответов:

Я не уверен насчет ядра 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-именами, но они также могут быть очень удобочитаемыми.

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

Единственным построителем, Наиболее точным для эффективной книги java, является StringBuilder. Единственное отличие, которое я вижу из примера, заключается в том, что этот конструктор не является внутренним классом строки.

Все методы возвращают объект builder в цепочку. а метод toString () - это метод build ().

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

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

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

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

Довольно хорошим примером из 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

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

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

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

ProcessBuilder в значительной степени является экземпляром шаблона builder, но не совсем использует соглашения об именовании 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 можно рассматривать как экземпляр шаблона builder:

 PreparedStatement stmt = conn.prepareStatement(getSql());
 stmt.setString(1, ...);
 stmt.setString(2, ...);
 ResultSet rs = stmt.executeQuery();
 ...
 stmt.setString(2, ...);
 rs = stmt.executeQuery();
 ...