Skip to content

Commit

Permalink
Update files structure (clxering#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
clxeringlab authored and clxering committed Feb 8, 2019
1 parent 417f7e2 commit abd7627
Show file tree
Hide file tree
Showing 101 changed files with 430 additions and 350 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Typically this constructor invocation will require many parameters that you don

In short, **the telescoping constructor pattern works, but it is hard to write client code when there are many parameters, and harder still to read it.** The reader is left wondering what all those values mean and must carefully count parameters to find out. Long sequences of identically typed parameters can cause subtle bugs. If the client accidentally reverses two such parameters, the compiler won’t complain, but the program will misbehave at runtime (Item 51).

简单地说,**可伸缩构造函数模式可以工作,但是当有很多参数时,编写客户端代码是很困难的,而且读起来更困难。** 读者想知道所有这些值是什么意思,必须仔细清点参数。相同类型参数的长序列会导致细微的错误。如果客户端不小心倒转了两个这样的参数,编译器不会报错,但是程序会在运行时出错([Item-51](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-8-Item-51-Design-method-signatures-carefully.md))。
简单地说,**可伸缩构造函数模式可以工作,但是当有很多参数时,编写客户端代码是很困难的,而且读起来更困难。** 读者想知道所有这些值是什么意思,必须仔细清点参数。相同类型参数的长序列会导致细微的错误。如果客户端不小心倒转了两个这样的参数,编译器不会报错,但是程序会在运行时出错([Item-51](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-8/Chapter-8-Item-51-Design-method-signatures-carefully.md))。

A second alternative(n.二中择一;adj.供选择的) when you’re faced with many optional parameters in a constructor 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:

Expand Down Expand Up @@ -103,15 +103,15 @@ cocaCola.setCarbohydrate(27);

Unfortunately, the JavaBeans pattern has serious disadvantages of its own. Because construction is split(vt.分离,分解) across multiple calls, a JavaBean may be in an inconsistent state partway through its construction. The class does not have the option of enforcing consistency merely by checking the validity of the constructor parameters. Attempting to use an object when it’s in an inconsistent(adj. 不一致的) state may cause failures that are far removed from the code containing the bug and hence(adv.因此) difficult to debug. A related disadvantage is that the JavaBeans pattern precludes the possibility of making a class immutable (Item 17) and requires added effort on the part of the programmer to ensure thread safety.

不幸的是,JavaBean 模式本身有严重的缺点。因为构建是在多个调用之间进行的,所以 JavaBean 可能在构建的过程中处于不一致的状态。该类不能仅通过检查构造函数参数的有效性来强制一致性。在不一致的状态下尝试使用对象可能会导致错误的发生,而包含这些错误的代码很难调试。一个相关的缺点是,JavaBean 模式排除了使类不可变的可能性([Item-17](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-4-Item-17-Minimize-mutability.md)),并且需要程序员额外的努力来确保线程安全。
不幸的是,JavaBean 模式本身有严重的缺点。因为构建是在多个调用之间进行的,所以 JavaBean 可能在构建的过程中处于不一致的状态。该类不能仅通过检查构造函数参数的有效性来强制一致性。在不一致的状态下尝试使用对象可能会导致错误的发生,而包含这些错误的代码很难调试。一个相关的缺点是,JavaBean 模式排除了使类不可变的可能性([Item-17](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-4/Chapter-4-Item-17-Minimize-mutability.md)),并且需要程序员额外的努力来确保线程安全。

It is possible to reduce these disadvantages by manually(adv.手动地) “freezing” the object when its construction is complete and not allowing it to be used until frozen, but this variant is unwieldy and rarely used in practice. Moreover, it can cause errors at runtime because the compiler cannot ensure that the programmer calls the freeze method on an object before using it.

通过在对象构建完成时手动「冻结」对象,并在冻结之前不允许使用对象,可以减少这些缺陷,但是这种变通方式很笨拙,在实践中很少使用。此外,它可能在运行时导致错误,因为编译器不能确保程序员在使用对象之前调用它的 freeze 方法。

Luckily, there is a third alternative that combines the safety of the telescoping constructor pattern with the readability of the JavaBeans pattern. It is a form of the Builder pattern [Gamma95]. Instead of making the desired object directly,the client calls 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 typically immutable. The builder is typically a static member class (Item 24) of the class itbuilds. Here’s how it looks in practice:

幸运的是,还有第三种选择,它结合了可伸缩构造函数模式的安全性和 JavaBean 模式的可读性。它是建造者模式的一种形式[Gamma95]。客户端不直接生成所需的对象,而是使用所有必需的参数调用构造函数(或静态工厂),并获得一个 builder 对象。然后,客户端在构建器对象上调用像 setter 这样的方法来设置每个感兴趣的可选参数。最后,客户端调用一个无参数的构建方法来生成对象,这通常是不可变的。构建器通常是它构建的类的静态成员类([Item-24](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-4-Item-24-Favor-static-member-classes-over-nonstatic.md))。下面是它在实际应用中的样子:
幸运的是,还有第三种选择,它结合了可伸缩构造函数模式的安全性和 JavaBean 模式的可读性。它是建造者模式的一种形式[Gamma95]。客户端不直接生成所需的对象,而是使用所有必需的参数调用构造函数(或静态工厂),并获得一个 builder 对象。然后,客户端在构建器对象上调用像 setter 这样的方法来设置每个感兴趣的可选参数。最后,客户端调用一个无参数的构建方法来生成对象,这通常是不可变的。构建器通常是它构建的类的静态成员类([Item-24](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-4/Chapter-4-Item-24-Favor-static-member-classes-over-nonstatic.md))。下面是它在实际应用中的样子:

```
// Builder Pattern
Expand Down Expand Up @@ -189,7 +189,7 @@ This client code is easy to write and, more importantly, easy to read. The Build

Validity(n.有效性) checks were omitted(v.遗漏,省略;adj.省去的) for brevity(n.简洁). To detect invalid parameters as soon as possible, check parameter validity in the builder’s constructor and methods.Check invariants involving multiple parameters in the constructor invoked by the build method. To ensure these invariants against attack, do the checks on object fields after copying parameters from the builder (Item 50). If a check fails, throw an IllegalArgumentException (Item 72) whose detail message indicates which parameters are invalid (Item 75).

为了简洁,省略了有效性检查。为了尽快检测无效的参数,请检查构建器的构造函数和方法中的参数有效性。检查构建方法调用的构造函数中涉及多个参数的不变量。为了确保这些不变量不受攻击,在从构建器复制参数之后检查对象字段([Item-50](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-8-Item-50-Make-defensive-copies-when-needed.md))。如果检查失败,抛出一个 IllegalArgumentException([Item-72](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-10-Item-72-Favor-the-use-of-standard-exceptions.md)),它的详细消息指示哪些参数无效([Item-75](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-10-Item-75-Include-failure-capture-information-in-detail-messages.md))。
为了简洁,省略了有效性检查。为了尽快检测无效的参数,请检查构建器的构造函数和方法中的参数有效性。检查构建方法调用的构造函数中涉及多个参数的不变量。为了确保这些不变量不受攻击,在从构建器复制参数之后检查对象字段([Item-50](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-8/Chapter-8-Item-50-Make-defensive-copies-when-needed.md))。如果检查失败,抛出一个 IllegalArgumentException([Item-72](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-10/Chapter-10-Item-72-Favor-the-use-of-standard-exceptions.md)),它的详细消息指示哪些参数无效([Item-75](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-10/Chapter-10-Item-75-Include-failure-capture-information-in-detail-messages.md))。

The Builder pattern is well suited to class hierarchies. Use a parallel hierarchy of builders, each nested in the corresponding class. Abstract classes have abstract builders; concrete classes have concrete builders. For example,consider an abstract class at the root of a hierarchy representing various kinds of pizza:

Expand Down Expand Up @@ -228,7 +228,7 @@ public abstract class Pizza {

Note that Pizza.Builder is a generic type with a recursive type parameter (Item 30). This, along with the abstract self method, allows method chaining to work properly in subclasses, without the need for casts. This workaround for the fact that Java lacks a self type is known as the simulated self-type idiom. Here are two concrete subclasses of Pizza, one of which represents a standard New-York-style pizza, the other a calzone. The former has a required size parameter,while the latter lets you specify whether sauce should be inside or out:

请注意,Pizza.Builder 是具有递归类型参数的泛型类型([Item-31](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-5-Item-31-Use-bounded-wildcards-to-increase-API-flexibility.md))。这与抽象 self 方法一起,允许方法链接在子类中正常工作,而不需要强制转换。对于 Java 缺少自类型这一事实,这种变通方法称为模拟自类型习惯用法。这里有两个具体的比萨子类,一个是标准的纽约风格的比萨,另一个是 calzone。前者有一个所需的大小参数,而后者让你指定酱料应该是内部还是外部:
请注意,Pizza.Builder 是具有递归类型参数的泛型类型([Item-31](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-5/Chapter-5-Item-31-Use-bounded-wildcards-to-increase-API-flexibility.md))。这与抽象 self 方法一起,允许方法链接在子类中正常工作,而不需要强制转换。对于 Java 缺少自类型这一事实,这种变通方法称为模拟自类型习惯用法。这里有两个具体的比萨子类,一个是标准的纽约风格的比萨,另一个是 calzone。前者有一个所需的大小参数,而后者让你指定酱料应该是内部还是外部:

```
import java.util.Objects;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

A singleton is simply a class that is instantiated(v.实例化) exactly once [Gamma95].Singletons typically represent either a stateless object such as a function (Item24) or a system component that is intrinsically unique. **Making a class a singleton can make it difficult to test its clients** because it’s impossible to substitute a mock implementation for a singleton unless it implements an interface that serves as its type.

单例是一个只实例化一次的类 [Gamma95]。单例通常表示无状态对象,比如函数([Item-24](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-4-Item-24-Favor-static-member-classes-over-nonstatic.md))或系统组件,它们在本质上是唯一的。**将一个类设计为单例会使它的客户端测试时变得困难,** 除非它实现了作为其类型的接口,否则无法用模拟实现来代替单例。
单例是一个只实例化一次的类 [Gamma95]。单例通常表示无状态对象,比如函数([Item-24](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-4/Chapter-4-Item-24-Favor-static-member-classes-over-nonstatic.md))或系统组件,它们在本质上是唯一的。**将一个类设计为单例会使它的客户端测试时变得困难,** 除非它实现了作为其类型的接口,否则无法用模拟实现来代替单例。

There are two common ways to implement singletons. Both are based on keeping the constructor private and exporting a public static member to provide access to the sole instance. In one approach, the member is a final field:

Expand All @@ -21,7 +21,7 @@ public class Elvis {

The private constructor is called only once, to initialize the public static final field Elvis.INSTANCE. The lack of a public or protected constructor guarantees a “monoelvistic” universe: exactly one Elvis instance will exist once the Elvis class is initialized—no more, no less. Nothing that a client does can change this, with one caveat: a privileged client can invoke the private constructor reflectively (Item 65) with the aid of the AccessibleObject.setAccessible method. If you need to defend against this attack, modify the constructor to make it throw an exception if it’s asked to create a second instance.

私有构造函数只调用一次,用于初始化 public static final 修饰的 Elvis 类型字段 INSTANCE。不使用 public 或 protected 的构造函数保证了「独一无二」的空间:一旦初始化了 Elvis 类,就只会存在一个 Elvis 实例,不多也不少。客户端所做的任何事情都不能改变这一点,但有一点需要注意:拥有特殊权限的客户端可以借助 AccessibleObject.setAccessible 方法利用反射调用私有构造函数([Item-65](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-9-Item-65-Prefer-interfaces-to-reflection.md))如果需要防范这种攻击,请修改构造函数,使其在请求创建第二个实例时抛出异常。
私有构造函数只调用一次,用于初始化 public static final 修饰的 Elvis 类型字段 INSTANCE。不使用 public 或 protected 的构造函数保证了「独一无二」的空间:一旦初始化了 Elvis 类,就只会存在一个 Elvis 实例,不多也不少。客户端所做的任何事情都不能改变这一点,但有一点需要注意:拥有特殊权限的客户端可以借助 AccessibleObject.setAccessible 方法利用反射调用私有构造函数([Item-65](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-9/Chapter-9-Item-65-Prefer-interfaces-to-reflection.md))如果需要防范这种攻击,请修改构造函数,使其在请求创建第二个实例时抛出异常。

***译注:使用 AccessibleObject.setAccessible 方法调用私有构造函数示例:***
```
Expand Down Expand Up @@ -64,7 +64,7 @@ One advantage of the static factory approach is that it gives you the flexibilit

***译注:static factory approach 等同于 static factory method***

静态工厂方法的一个优点是,它可以在不更改 API 的情况下决定类是否是单例。工厂方法返回唯一的实例,但是可以对其进行修改,为调用它的每个线程返回一个单独的实例。第二个优点是,如果应用程序需要的话,可以编写泛型的单例工厂([Item-30](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-5-Item-30-Favor-generic-methods.md))。使用静态工厂的最后一个优点是方法引用能够作为一个提供者,例如 `Elvis::getInstance``Supplier<Elvis>` 的提供者。除非能够与这些优点沾边,否则使用 public 字段的方式更可取。
静态工厂方法的一个优点是,它可以在不更改 API 的情况下决定类是否是单例。工厂方法返回唯一的实例,但是可以对其进行修改,为调用它的每个线程返回一个单独的实例。第二个优点是,如果应用程序需要的话,可以编写泛型的单例工厂([Item-30](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-5/Chapter-5-Item-30-Favor-generic-methods.md))。使用静态工厂的最后一个优点是方法引用能够作为一个提供者,例如 `Elvis::getInstance``Supplier<Elvis>` 的提供者。除非能够与这些优点沾边,否则使用 public 字段的方式更可取。

***译注 1:原文方法引用可能是笔误,修改为 `Elvis::getInstance`***

Expand All @@ -77,7 +77,7 @@ obj.leaveTheBuilding();

To make a singleton class that uses either of these approaches serializable (Chapter 12), it is not sufficient merely to add implements Serializable to its declaration. To maintain(vt.维持) the singleton guarantee(n.保证), declare all instance fields transient and provide a readResolve method (Item 89). Otherwise, each time a serialized instance is deserialized, a new instance will be created, leading,in the case of our example, to spurious(adj.虚假的) Elvis sightings. To prevent this from happening, add this readResolve method to the Elvis class:

要使单例类使用这两种方法中的任何一种([12-Serialization]( https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-12-Introduction.md)),仅仅在其声明中添加实现 serializable 是不够的。要维护单例保证,应声明所有实例字段为 transient,并提供 readResolve 方法([Item-89](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-12-Item-89-For-instance-control-prefer-enum-types-to-readResolve.md))。否则,每次反序列化实例时,都会创建一个新实例,在我们的示例中,这会导致出现虚假的 Elvis。为了防止这种情况发生,将这个 readResolve 方法添加到 Elvis 类中:
要使单例类使用这两种方法中的任何一种([12-Serialization]( https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-12/Chapter-12-Introduction.md)),仅仅在其声明中添加实现 serializable 是不够的。要维护单例保证,应声明所有实例字段为 transient,并提供 readResolve 方法([Item-89](https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/master/Chapter-12/Chapter-12-Item-89-For-instance-control-prefer-enum-types-to-readResolve.md))。否则,每次反序列化实例时,都会创建一个新实例,在我们的示例中,这会导致出现虚假的 Elvis。为了防止这种情况发生,将这个 readResolve 方法添加到 Elvis 类中:

```
// readResolve method to preserve singleton property
Expand Down
Loading

0 comments on commit abd7627

Please sign in to comment.