15

Joshua Bloch 的Effective Java描述了一种构建器模式,该模式可用于构建具有多个可选自定义参数的对象。他为 Builder 函数建议的命名约定,“模拟在 Ada 和 Python 中找到的命名可选参数”,似乎不符合 Java 的标准命名约定。Java 函数往往依赖于一个动词来启动函数,然后是一个基于名词的短语来描述它的作用。Builder 类只有该函数要定义的变量的名称。

Java 标准库中是否有任何使用 Builder 模式的 API?在继续使用本书之前,我想将书中的建议与核心 Java 库中的实际实现进行比较。

4

7 回答 7

17

我不确定核心 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 广泛使用该模式。这不是建造者模式,而是另一种相关的建造形式。

于 2010-01-30T19:51:19.580 回答
6

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();
于 2016-06-10T13:00:37.800 回答
5

唯一对 Effective java 书籍最准确的构建器是 StringBuilder。我从示例中看到的唯一区别是此构建器不是 String 的内部类。

所有方法都将构建器对象返回到链中。toString() 方法是 build() 方法。

于 2011-03-23T16:23:36.053 回答
5

Java 8 Core API 的一个很好的例子是Calendar,例如你可以使用:

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

另一个很好的例子Java 7Locale,使用:

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

构建器模式在不可变对象的上下文中最有用。有趣的是,Java 中有许多可变构建器,StringBuilder这是最常见的一种。Java 8 中的可变构建器:

  • Stream.Builder
  • IntStream.Builder
  • LongStream.Builder
  • DoubleStream.Builder
于 2017-11-17T17:03:12.953 回答
4

SAXParser似乎是一个很好的例子:

  • SAXParser- 导向器
  • ContentHandler- 生成器

的典型用法SAXParser与 Builder 相同:

// Create Director
SAXParser parser = new org.apache.xerces.parsers.SAXParser();  
// Create Concrete Builder (our own class)
IndentingContentHandler handler = new IndentingContentHandler();
// Set Builder to Director
parser.setContentHandler(handler);
// Build
parser.parse(new InputSource(new FileReader(fileName));
// Get indented XML as String from handler
String indentedXML = handler.getResult();
于 2012-01-03T09:12:27.863 回答
1

ProcessBuilder 在很大程度上是构建器模式的一个实例,但并不完全使用 java 命名约定。

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

在 SQL 包中,PreparedStatement 可以被认为是构建器模式的一个实例:

PreparedStatement stmt = conn.prepareStatement(getSql());
 stmt.setString(1, ...);
 stmt.setString(2, ...);
 结果集 rs = stmt.executeQuery();
 ...
 stmt.setString(2, ...);
 rs = stmt.executeQuery();
 ...
于 2010-02-04T20:18:34.007 回答
0

它只是在标准库中定义(未实现),但是,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");
于 2010-01-30T19:49:03.937 回答