Joshua Bloch的 Effective Java 描述了一种Builder模式,可用于构建具有多个可选定制参数的对象。他为Builder函数建议的命名约定,“模拟在Ada和Python中找到的命名可选参数”,似乎不符合Java的标准命名约定。 Java函数往往依赖于使用动词来启动函数,然后依靠基于名词的短语来描述它的作用。 Builder类只有该函数定义的变量名称。
Java标准库中是否有使用Builder模式的API?我想在继续使用之前,将本书中的建议与核心Java库集中的实际实现进行比较。
答案 0 :(得分:17)
我不确定核心JDK,但在Guava中可以找到很好的例子。 MapMaker
可能是我能想到的最好的例子。例如,来自docs:
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广泛使用该模式。这不是构建器模式,而是替代和相关的构造形式。
答案 1 :(得分:5)
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();
答案 2 :(得分:4)
有效的java书籍中唯一最准确的构建器是StringBuilder。 我从示例中看到的唯一区别是此构建器不是String的内部类。
所有方法都将构建器对象返回到链。而toString()方法是build()方法。
答案 3 :(得分:2)
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();
答案 4 :(得分:2)
来自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
答案 5 :(得分:1)
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(); ...
答案 6 :(得分: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");