1. Static factories and constructors share a limitation: they do not scale well to large numbers of optional parameters.
2. Telescoping constructor pattern provides a constructor with only the required parameters, another with a single optional parameter, a third with two optional parameters, and so on, culminating in a constructor with all the optional parameters. When you want to create an instance, you use the constructor with the shortest parameter list containing all the parameters you want to set. Typically this constructor invocation will require many parameters that you don’t want to set, but you’re forced to pass a value for them anyway. So it is hard to write client code when there are many parameters, and harder still to read it.
3. A second alternative when you are faced with many constructor parameters is the JavaBeans pattern, in which you call a parameterless constructor to create the object and then call setter methods to set each required parameter and each optional parameter of interest. However a JavaBean may be in an inconsistent state partway through its construction. Also the JavaBeans pattern precludes the possibility of making a class immutable, and requires added effort on the part of the programmer to ensure thread safety.
4. Instead of making the desired object directly, the client can call a constructor (or static factory) with all of the required parameters and gets a builder object. Then the client calls setter-like methods on the builder object to set each optional parameter of interest. Finally, the client calls a parameterless build method to generate the object, which is immutable. The builder can be a static member class of the class it builds. The builder’s setter methods return the builder itself so that invocations can be chained.
5. Like a constructor, a builder can impose invariants on its parameters. The build method can check these invariants. It is critical that they be checked after copying the parameters from the builder to the object, and that they be checked on the object fields rather than the builder fields (in case the parameters are mutable, the object can have defensive copy of the parameters). If any invariants are violated, the build method should throw an IllegalStateException. The exception’s detail method should indicate which invariant is violated
6. Another way to impose invariants involving multiple parameters is to have setter methods take entire groups of parameters on which some invariant must hold. If the invariant isn’t satisfied, the setter method throws an IllegalArgumentException. This has the advantage of detecting the invariant failure as soon as the invalid parameters are passed, instead of waiting for build to be invoked.
7. A minor advantage of builders over constructors is that builders can have multiple var-args parameters.(Actually var-args are same as array, so it’s not important.)
8. A builder whose parameters have been set makes a fine Abstract Factory. (why?) In other words, a client can pass such a builder to a method to enable the method to create one or more objects for the client. To enable this usage, you need a type to represent the builder. A single generic type suffices for all builders, no matter what type of object they’re building:
// A builder for objects of type T public interface Builder<T> { public T build(); }
9. Methods that take a Builder instance would typically constrain the builder’s type parameter using a bounded wildcard type. For example, here is a method that builds a tree using a client-provided Builder instance to build each node:
Tree buildTree(Builder<? extends Node> nodeBuilder) { ... }
10. The traditional Abstract Factory implementation in Java has been the Class object, with the newInstance method playing the part of the build method. The newInstance method always attempts to invoke the class’s parameterless constructor, which may not even exist. You don’t get a compile-time error if the class has no accessible parameterless constructor. Instead, the client code must cope with InstantiationException or IllegalAccessException at runtime, which is ugly and inconvenient. Also, the newInstance method propagates any exceptions thrown by the parameterless constructor, even though newInstance lacks the corresponding throws clauses. In other words, Class.newInstance breaks compile-time exception checking.
11. In order to create an object, you must first create its builder. While the cost of creating the builder is unlikely to be noticeable in practice, it could be a problem in some performance critical situations.
12. The Builder pattern is more verbose than the telescoping constructor pattern, so it should be used only if there are enough parameters, say, four or more.
13. In summary, the Builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters, especially if most of those parameters are optional. Client code is much easier to read and write with builders than with the traditional telescoping constructor pattern, and builders are much safer than JavaBeans.
相关推荐
Item 2: Consider a builder when faced with many constructor parameters Item 3: Enforce the singleton property with a private constructor or an enum type Item 4: Enforce noninstantiability with a ...
Common case: Suppose you’re faced with N equally probable choices, and you receive a message that narrows it down to M choices. The probability that message would be sent is M*(1/N) so the amount ...
2. 勇气与选择:\"Some when faced with a bloody battle simply give in, but for some surrender is unacceptable, even though they know it would be a fight to the death.\" 这里阐述了面对困难时的两种态度:...
When faced with solving such non-smooth problems, methods like the genetic algorithm or the more recently developed pattern search methods, both found in the Genetic Algorithm and Direct Search ...
Achieving efficient code through performance tuning is one of the key challenges faced by many programmers. This book looks at Qt programming from a performance perspective. You’ll explore the ...
Exploring real life applications, we will explore the Zend Framework 2 components, as well as throwing some light on best practices and design concerns faced when building complex MVC applications. ...
2. `be faced with`表示面临或面对某事,如:“The company is faced with a serious financial problem now.” 3. `face up to sth`强调勇敢面对(困难或不快之事),比如:“I have grown up now and I have to ...
Most importantly, this book highlights the architectural differences between technologies that are the critical factors to consider when choosing a database platform for new and upcoming projects. ...
1)许多国家都面临……的问题,例如:“Many nations have been faced with the problem of…” 2)最近这个问题引起了关注:“Recently the problem has been brought into focus.” 4)最近这个问题已引起广泛关注...
Actually one of the most critical and badly tuned loops I have been faced with is probably the learning loop between industry and the academic world Without pretentiousness my intention when starting ...
Chapter 2: GoF Design Patterns Chapter 3: SOLID Design Principles Chapter 4: Requirement Specification for a Modular Web Shop App Chapter 5: Symfony at a Glance Chapter 6: Building the Core Module ...