Skip to content

Commit acca795

Browse files
第二十五章 设计模式 翻译更新(“改变接口”小节翻译完成) (lingcoder#379)
* 第二十五章 设计模式 翻译更新(“函数对象”小节翻译完成) * 第二十五章 设计模式 翻译更新(“改变接口”小节翻译完成)
1 parent 10422d7 commit acca795

File tree

1 file changed

+137
-1
lines changed

1 file changed

+137
-1
lines changed

docs/book/25-Patterns.md

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1043,8 +1043,144 @@ Bisection.algorithm
10431043
每一个 `Algorithm` 接口的实现,都实现了不同的 `algorithm()` 方法。在 `FindMinama` 中,将会创建一个算法的列表(这就是所谓的“链”),而 `minima()` 方法只是遍历这个列表,然后找到能够成功执行的算法而已。
10441044

10451045
<!-- Changing the Interface -->
1046-
## 接口改变
1046+
## 改变接口
10471047

1048+
有时候我们需要解决的问题很简单,仅仅是“我没有需要的接口”而已。有两种设计模式用来解决这个问题:*适配器模式* 接受一种类型并且提供一个对其他类型的接口。*外观模式* 为一组类创建了一个接口,这样做只是为了提供一种更方便的方法来处理库或资源。
1049+
1050+
### 适配器模式(Adapter
1051+
1052+
当我们手头有某个类,而我们需要的却是另外一个类,我们就可以通过 *适配器模式* 来解决问题。唯一需要做的就是产生出我们需要的那个类,有许多种方法可以完成这种适配。
1053+
1054+
```java
1055+
// patterns/adapt/Adapter.java
1056+
// Variations on the Adapter pattern
1057+
// {java patterns.adapt.Adapter}
1058+
package patterns.adapt;
1059+
1060+
class WhatIHave {
1061+
public void g() {}
1062+
public void h() {}
1063+
}
1064+
1065+
interface WhatIWant {
1066+
void f();
1067+
}
1068+
1069+
class ProxyAdapter implements WhatIWant {
1070+
WhatIHave whatIHave;
1071+
ProxyAdapter(WhatIHave wih) {
1072+
whatIHave = wih;
1073+
}
1074+
@Override
1075+
public void f() {
1076+
// Implement behavior using
1077+
// methods in WhatIHave:
1078+
whatIHave.g();
1079+
whatIHave.h();
1080+
}
1081+
}
1082+
1083+
class WhatIUse {
1084+
public void op(WhatIWant wiw) {
1085+
wiw.f();
1086+
}
1087+
}
1088+
1089+
// Approach 2: build adapter use into op():
1090+
class WhatIUse2 extends WhatIUse {
1091+
public void op(WhatIHave wih) {
1092+
new ProxyAdapter(wih).f();
1093+
}
1094+
}
1095+
1096+
// Approach 3: build adapter into WhatIHave:
1097+
class WhatIHave2 extends WhatIHave implements WhatIWant {
1098+
@Override
1099+
public void f() {
1100+
g();
1101+
h();
1102+
}
1103+
}
1104+
1105+
// Approach 4: use an inner class:
1106+
class WhatIHave3 extends WhatIHave {
1107+
private class InnerAdapter implements WhatIWant {
1108+
@Override
1109+
public void f() {
1110+
g();
1111+
h();
1112+
}
1113+
}
1114+
public WhatIWant whatIWant() {
1115+
return new InnerAdapter();
1116+
}
1117+
}
1118+
1119+
public class Adapter {
1120+
public static void main(String[] args) {
1121+
WhatIUse whatIUse = new WhatIUse();
1122+
WhatIHave whatIHave = new WhatIHave();
1123+
WhatIWant adapt= new ProxyAdapter(whatIHave);
1124+
whatIUse.op(adapt);
1125+
// Approach 2:
1126+
WhatIUse2 whatIUse2 = new WhatIUse2();
1127+
whatIUse2.op(whatIHave);
1128+
// Approach 3:
1129+
WhatIHave2 whatIHave2 = new WhatIHave2();
1130+
whatIUse.op(whatIHave2);
1131+
// Approach 4:
1132+
WhatIHave3 whatIHave3 = new WhatIHave3();
1133+
whatIUse.op(whatIHave3.whatIWant());
1134+
}
1135+
}
1136+
```
1137+
1138+
我想冒昧的借用一下术语“proxy”(代理),因为在 *《设计模式》* 里,他们坚持认为一个代理(proxy)必须拥有和它所代理的对象一模一样的接口。但是,如果把这两个词一起使用,叫做“代理适配器(proxy adapter)”,似乎更合理一些。
1139+
1140+
### 外观模式(Façade)
1141+
1142+
当我想方设法试图将需求初步(first-cut)转化成对象的时候,通常我使用的原则是:
1143+
1144+
>“把所有丑陋的东西都隐藏到对象里去”。
1145+
1146+
基本上说,*外观模式* 干的就是这个事情。如果我们有一堆让人头晕的类以及交互(Interactions),而它们又不是客户端程序员必须了解的,那我们就可以为客户端程序员创建一个接口只提供那些必要的功能。
1147+
1148+
外观模式经常被实现为一个符合单例模式(Singleton)的抽象工厂(abstract factory)。当然,你可以通过创建包含 **静态** 工厂方法(static factory methods)的类来达到上述效果。
1149+
1150+
```java
1151+
// patterns/Facade.java
1152+
1153+
class A { A(int x) {} }
1154+
1155+
class B { B(long x) {} }
1156+
1157+
class C { C(double x) {} }
1158+
1159+
// Other classes that aren't exposed by the
1160+
// facade go here ...
1161+
public class Facade {
1162+
static A makeA(int x) { return new A(x); }
1163+
static B makeB(long x) { return new B(x); }
1164+
static C makeC(double x) { return new C(x); }
1165+
public static void main(String[] args) {
1166+
// The client programmer gets the objects
1167+
// by calling the static methods:
1168+
A a = Facade.makeA(1);
1169+
B b = Facade.makeB(1);
1170+
C c = Facade.makeC(1.0);
1171+
}
1172+
}
1173+
```
1174+
1175+
《设计模式》给出的例子并不是真正的 *外观模式* ,而仅仅是一个类使用了其他的类而已。
1176+
1177+
#### 包(Package)作为外观模式的变体
1178+
1179+
我感觉,*外观模式* 更倾向于“过程式的(procedural)”,也就是非面向对象的(non-object-oriented):我们是通过调用某些函数才得到对象。它和抽象工厂(Abstract factory)到底有多大差别呢?*外观模式* 关键的一点是隐藏某个库的一部分类(以及它们的交互),使它们对于客户端程序员不可见,这样那些类的接口就更加简练和易于理解了。
1180+
1181+
其实,这也正是 Java 的 packaging(包)的功能所完成的事情:在库以外,我们只能创建和使用被声明为公共(public)的那些类;所有非公共(non-public)的类只能被同一 package 的类使用。看起来,*外观模式* 似乎是 Java 内嵌的一个功能。
1182+
1183+
公平起见,*《设计模式》* 主要是写给 C++ 读者的。尽管 C++ 有命名空间(namespaces)机制来防止全局变量和类名称之间的冲突,但它并没有提供类隐藏的机制,而在 Java 里我们可以通过声明 non-public 类来实现这一点。我认为,大多数情况下 Java 的 package 功能就足以解决针对 *外观模式* 的问题了。
10481184

10491185
<!-- Interpreter: Run-Time Flexibility -->
10501186
## 解释器

0 commit comments

Comments
 (0)