@@ -66,17 +66,19 @@ class TrustTaxStrategy extends DefaultTaxStrategy<Trust> {
66
66
}
67
67
```
68
68
69
- 可以定义一个收入为 ` 100,000.00 ` 美元的人和两个收入相同的信托人,一个非营利组织和一个非营利组织 。
69
+ 可以定义一个收入为 ` 100,000.00 ` 美元的人和两个收入相同的信托人,一个非营利组织和一个营利组织 。
70
70
71
71
``` java
72
72
Person person = new Person (10000000 );
73
73
Trust nonProfit = new Trust (10000000 , true );
74
74
Trust forProfit = new Trust (10000000 , false );
75
75
```
76
76
77
- 按照良好的做法,我们用长整数表示所有的货币价值,例如收入或税收,以毫秒为单位表示价值(参见“有效性的一般编程”一章中的“避免浮动和双重,如果需要确切答案” ` Java ` 由 ` Joshua Bloch ` ,` Addison-Wesley ` 编写)。
77
+ 按照良好的做法,我们用长整数表示所有的货币价值,例如收入或税收,以毫秒为单位表示价值(参见“有效性的一般编程”一章中的“避免浮动和双重,如果需要确切答
78
+ 案” ` Java ` 由 ` Joshua Bloch ` ,` Addison-Wesley ` 编写)。
78
79
79
- 对于每个纳税人` P ` ,可能有许多可能的计算税收策略。 每个策略实现接口 ` TaxStrategy<P> ` ,该接口指定一个方法计算 ` Tax ` ,该方法将 ` P ` 作为纳税人的参数并返回所支付的税金。 类` DefaultTaxStrategy ` 通过将收入乘以 ` 40% ` 的固定税率来计算税额,而 ` DodgingTaxStrategy ` 则始终计算零税额:
80
+ 对于每个纳税人` P ` ,可能有许多可能的计算税收策略。 每个策略实现接口 ` TaxStrategy<P> ` ,该接口指定一个方法计算 ` Tax ` ,该方法将 ` P ` 作为纳税人的参数
81
+ 并返回所支付的税金。 类` DefaultTaxStrategy ` 通过将收入乘以 ` 40% ` 的固定税率来计算税额,而 ` DodgingTaxStrategy ` 则始终计算零税额:
80
82
81
83
``` java
82
84
TaxStrategy<Person > defaultStrategy = new DefaultStrategy<Person > ();
@@ -85,7 +87,8 @@ assert defaultStrategy.computeTax(person) == 4000000;
85
87
assert dodgingStrategy. computeTax(person) == 0 ;
86
88
```
87
89
88
- 当然,我们的例子是为了说明而简化的 - 我们不建议您使用这些策略中的任何一种来计算税收! 但是应该清楚这些技术是如何延伸到更复杂的纳税人和税收策略的。最后,如果信托是非营利组织,并且使用默认税策略,则 ` TrustTaxStrategy ` 类计算零税额:
90
+ 当然,我们的例子是为了说明而简化的 - 我们不建议您使用这些策略中的任何一种来计算税收! 但是应该清楚这些技术是如何延伸到更复杂的纳税人和税收策略的。最
91
+ 后,如果信托是非营利组织,并且使用默认税策略,则 ` TrustTaxStrategy ` 类计算零税额:
89
92
90
93
``` java
91
94
TaxStrategy<Trust > trustStrategy = new TrustTaxStrategy ();
@@ -99,13 +102,20 @@ assert trustStrategy.computeTax(forProfit) == 4000000;
99
102
trustStrategy. computeTax(person); // 编译报错
100
103
```
101
104
102
- 没有泛型,` TrustTaxStrategy ` 的 ` computeTax ` 方法将不得不接受 ` TaxPayer ` 类型的参数并将其转换为 ` Trust ` 类型,并且错误会在运行时抛出异常,而不是在编译时捕获。
105
+ 没有泛型,` TrustTaxStrategy ` 的 ` computeTax ` 方法将不得不接受 ` TaxPayer ` 类型的参数并将其转换为 ` Trust ` 类型,并且错误会在运行时抛出异常,而不是
106
+ 在编译时捕获。
103
107
104
- 这个例子说明了许多面向对象程序中的结构化技术 - 即并行类层次结构。在这种情况下,一个类层次结构由 ` TaxPayer ` ,` Person ` 和 ` Trust ` 组成。并行类层次结构由与以下每个策略相对应的策略组成:两种策略:` DefaultTaxStrategy ` 和 ` DutingTaxStrategy ` 适用于任何 ` TaxPayer ` ,没有专门的策略适用于 ` Person ` ,并且 ` Trust ` 有一个专门的策略。
108
+ 这个例子说明了许多面向对象程序中的结构化技术 - 即并行类层次结构。在这种情况下,一个类层次结构由 ` TaxPayer ` ,` Person ` 和 ` Trust ` 组成。并行类层次结
109
+ 构由与以下每个策略相对应的策略组成:两种策略:` DefaultTaxStrategy ` 和 ` DutingTaxStrategy ` 适用于任何 ` TaxPayer ` ,没有专门的策略适用于
110
+ ` Person ` ,并且 ` Trust ` 有一个专门的策略。
105
111
106
- 通常,这种并行层次结构之间存在某种联系。在这种情况下,与给定 ` TaxPayer ` 并行的 ` TaxStrategy ` 的 ` computeTax ` 方法需要具有相应类型的参数;例如,` TrustTaxStrategy ` 的 ` computeTax ` 方法需要一个 ` Trust ` 类型的参数。对于泛型,我们可以在类型本身中整齐地捕捉这个连接。在这种情况下,` TaxStrategy<P> ` 的 ` computeTax ` 方法需要 ` P ` 类型的参数,其中 ` P ` 必须是 ` TaxPayer ` 的子类。使用我们在此描述的技术,泛型通常可用于捕获其他并行类层次结构中的类似关系。
112
+ 通常,这种并行层次结构之间存在某种联系。在这种情况下,与给定 ` TaxPayer ` 并行的 ` TaxStrategy ` 的 ` computeTax ` 方法需要具有相应类型的参数;例如,
113
+ ` TrustTaxStrategy ` 的 ` computeTax ` 方法需要一个 ` Trust ` 类型的参数。对于泛型,我们可以在类型本身中整齐地捕捉这个连接。在这种情况下,
114
+ ` TaxStrategy<P> ` 的 ` computeTax ` 方法需要 ` P ` 类型的参数,其中 ` P ` 必须是 ` TaxPayer ` 的子类。使用我们在此描述的技术,泛型通常可用于捕获其他并行
115
+ 类层次结构中的类似关系。
107
116
108
- 具有递归泛型的高级策略模式在策略模式的更高级用途中,对象包含要应用于其的策略。建模这种情况需要递归泛型类型,并利用一种技巧为此指定一个泛型类型。修订后的战略模式如示例 ` 9-7 ` 所示。在高级版本中,每个纳税人对象都包含自己的税收策略,每种纳税人的构造函数都包含一个税收策略作为附加参数:
117
+ 具有递归泛型的高级策略模式在策略模式的更高级用途中,对象包含要应用于其的策略。建模这种情况需要递归泛型类型,并利用一种技巧为此指定一个泛型类型。修订
118
+ 后的战略模式如示例 ` 9-7 ` 所示。在高级版本中,每个纳税人对象都包含自己的税收策略,每种纳税人的构造函数都包含一个税收策略作为附加参数:
109
119
110
120
``` java
111
121
Person normal = new Person (10000000 , new DefaultTaxStrategy<Person > ());
@@ -125,7 +135,8 @@ assert forProfit.computeTax() == 4000000;
125
135
126
136
这种结构往往是可取的,因为可以将给定的税收策略直接与给定的纳税人联系起来。
127
137
128
- 之前,我们使用了 ` TaxPayer ` 类和接口 ` TaxStrategy<P> ` ,其中类型变量 ` P ` 代表策略适用的 ` TaxPayer ` 的子类。 现在我们必须将类型参数 ` P ` 添加到两者中,以便类 ` TaxPayer<P> ` 可以具有类型 ` TaxStrategy<P> ` 的字段。 类型变量 ` P ` 的新声明必须是递归的,如 ` TaxPayer ` 类的新标题所示:
138
+ 之前,我们使用了 ` TaxPayer ` 类和接口 ` TaxStrategy<P> ` ,其中类型变量 ` P ` 代表策略适用的 ` TaxPayer ` 的子类。 现在我们必须将类型参数 ` P ` 添加到两者
139
+ 中,以便类 ` TaxPayer<P> ` 可以具有类型 ` TaxStrategy<P> ` 的字段。 类型变量 ` P ` 的新声明必须是递归的,如 ` TaxPayer ` 类的新标题所示:
129
140
130
141
``` java
131
142
class TaxPayer <P extends TaxPayer<P > >
@@ -138,9 +149,11 @@ interface Comparable<T extends Comparable<T>>
138
149
class Enum<E extends Enum<E > >
139
150
```
140
151
141
- 在所有这三种情况下,类或接口都是类型层次结构的基类,类型参数代表基类的特定子类。 因此,`TaxPayer<P > ` 中的 `P ` 代表特定类型的纳税人,例如 `Person ` 或 `Trust `; 就像 `Comparable<T > ` 中的 `T ` 代表被比较的特定类,比如 `String `; 或 `Enum<E > ` 中的 `E ` 表示特定枚举类型,如季节。
152
+ 在所有这三种情况下,类或接口都是类型层次结构的基类,类型参数代表基类的特定子类。 因此,`TaxPayer<P > ` 中的 `P ` 代表特定类型的纳税人,例如 `Person `
153
+ 或 `Trust `; 就像 `Comparable<T > ` 中的 `T ` 代表被比较的特定类,比如 `String `; 或 `Enum<E > ` 中的 `E ` 表示特定枚举类型,如季节。
142
154
143
- 纳税人类包含一个税收策略字段和一个将纳税人转到税收策略的方法,以及一个像 `TaxPayer ` 中使用的 `P ` 一样的递归声明。 总的来说,我们可能期望它看起来像这样:
155
+ 纳税人类包含一个税收策略字段和一个将纳税人转到税收策略的方法,以及一个像 `TaxPayer ` 中使用的 `P ` 一样的递归声明。 总的来说,我们可能期望它看起来像这
156
+ 样:
144
157
145
158
```java
146
159
// not well-typed!
@@ -155,9 +168,12 @@ class Person extends TaxPayer<Person> { ... }
155
168
class Trust extends TaxPayer<Trust > { ... }
156
169
```
157
170
158
- 但编译器拒绝上面的类型错误。 问题是这有 ` TaxPayer<P> ` 类型,而 ` computeTax ` 的参数必须有 ` P ` 类型。 事实上,在每个具体的纳税人类别中,例如人员或信任,这种情况确实具有类型 ` P ` ; 例如,` Person ` 扩展了 ` TaxPayer<Person> ` ,所以 ` P ` 与此类中的 ` Person ` 相同。 所以,实际上,这将与 ` P ` 具有相同的类型,但类型系统不知道!
171
+ 但编译器拒绝上面的类型错误。 问题是这有 ` TaxPayer<P> ` 类型,而 ` computeTax ` 的参数必须有 ` P ` 类型。 事实上,在每个具体的纳税人类别中,例如人员或信
172
+ 任,这种情况确实具有类型 ` P ` ; 例如,` Person ` 扩展了 ` TaxPayer<Person> ` ,所以 ` P ` 与此类中的 ` Person ` 相同。 所以,实际上,这将与 ` P ` 具有相同的
173
+ 类型,但类型系统不知道!
159
174
160
- 我们可以用一个技巧来解决这个问题。 在基类 ` TaxPayer<P> ` 中,我们定义了一个抽象方法 ` getThis ` ,其目的是返回与此相同的值,但赋予其类型 ` P ` . 该方法在与特定种类的纳税人相对应的每个类中实例化,例如 ` Person ` 或 ` Trust ` ,其类型实际上与 ` P ` 类型相同。 概括地说,修正的代码现在看起来像这样:
175
+ 我们可以用一个技巧来解决这个问题。 在基类 ` TaxPayer<P> ` 中,我们定义了一个抽象方法 ` getThis ` ,其目的是返回与此相同的值,但赋予其类型 ` P ` . 该方法在
176
+ 与特定种类的纳税人相对应的每个类中实例化,例如 ` Person ` 或 ` Trust ` ,其类型实际上与 ` P ` 类型相同。 概括地说,修正的代码现在看起来像这样:
161
177
162
178
``` java
163
179
// now correctly typed
@@ -177,9 +193,12 @@ final class Trust extends TaxPayer<Trust> {
177
193
}
178
194
```
179
195
180
- 与以前的代码不同之处在于粗体。 这个的出现被调用 ` getThis ` 所取代; 方法 ` getThis ` 在基类中声明为抽象,并且在基类的每个最终子类中都适当地实例化。 基类 ` TaxPayer<P> ` 必须声明为 ` abstract ` ,因为它声明了 ` getThis ` 的类型,但未声明正文。 ` getThis ` 的主体在 ` Person ` 和 ` Trust ` 的最后一个子类中声明。
196
+ 与以前的代码不同之处在于粗体。 这个的出现被调用 ` getThis ` 所取代; 方法 ` getThis ` 在基类中声明为抽象,并且在基类的每个最终子类中都适当地实例化。 基
197
+ 类 ` TaxPayer<P> ` 必须声明为 ` abstract ` ,因为它声明了 ` getThis ` 的类型,但未声明正文。 ` getThis ` 的主体在 ` Person ` 和 ` Trust ` 的最后一个子类中声
198
+ 明。
181
199
182
- 由于信任被声明为最终的,所以它不能有子类。 假设我们想要一个 ` Trust ` 的子类 ` NonProfitTrust ` 。 那么我们不仅需要删除 ` Trust ` 类的最终声明,还需要为其添加一个类型参数。 以下是所需代码的草图:
200
+ 由于信任被声明为最终的,所以它不能有子类。 假设我们想要一个 ` Trust ` 的子类 ` NonProfitTrust ` 。 那么我们不仅需要删除 ` Trust ` 类的最终声明,还需要为
201
+ 其添加一个类型参数。 以下是所需代码的草图:
183
202
184
203
``` java
185
204
abstract class Trust <T extends Trust<T > > extends TaxPayer<T > { ... }
0 commit comments