Skip to content

Commit ffd4959

Browse files
committed
Signed-off-by: Trency <trency92@gmail.com>
Fix issue lingcoder#28: 翻译类型信息部分 动态代理小节
1 parent 4aca12b commit ffd4959

File tree

1 file changed

+197
-0
lines changed

1 file changed

+197
-0
lines changed

docs/book/19-Type-Information.md

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,6 +1405,203 @@ java ShowMethods ShowMethods
14051405
<!-- Dynamic Proxies -->
14061406
## 动态代理
14071407

1408+
*代理*是基本的设计模式之一。它是你插入的对象,代替“真实”对象以提供其他或不同的操作---这些操作通常涉及到与“真实”对象的通信,因此代理通常充当中间对象。这是一个简单的示例,显示代理的结构:
1409+
1410+
```java
1411+
// typeinfo/SimpleProxyDemo.java
1412+
1413+
interface Interface {
1414+
void doSomething();
1415+
void somethingElse(String arg);
1416+
}
1417+
1418+
class RealObject implements Interface {
1419+
@Override
1420+
public void doSomething() {
1421+
System.out.println("doSomething");
1422+
}
1423+
@Override
1424+
public void somethingElse(String arg) {
1425+
System.out.println("somethingElse " + arg);
1426+
}
1427+
}
1428+
1429+
class SimpleProxy implements Interface {
1430+
private Interface proxied;
1431+
SimpleProxy(Interface proxied) {
1432+
this.proxied = proxied;
1433+
}
1434+
@Override
1435+
public void doSomething() {
1436+
System.out.println("SimpleProxy doSomething");
1437+
proxied.doSomething();
1438+
}
1439+
@Override
1440+
public void somethingElse(String arg) {
1441+
System.out.println(
1442+
"SimpleProxy somethingElse " + arg);
1443+
proxied.somethingElse(arg);
1444+
}
1445+
}
1446+
1447+
class SimpleProxyDemo {
1448+
public static void consumer(Interface iface) {
1449+
iface.doSomething();
1450+
iface.somethingElse("bonobo");
1451+
}
1452+
public static void main(String[] args) {
1453+
consumer(new RealObject());
1454+
consumer(new SimpleProxy(new RealObject()));
1455+
}
1456+
}
1457+
/* Output:
1458+
doSomething
1459+
somethingElse bonobo
1460+
SimpleProxy doSomething
1461+
doSomething
1462+
SimpleProxy somethingElse bonobo
1463+
somethingElse bonobo
1464+
*/
1465+
```
1466+
1467+
因为`consumer()`接受`Interface`,所以它不知道获得的是`RealObject`还是`SimpleProxy`,因为两者都实现了`Interface`
1468+
但是,在客户端和`RealObject`之间插入的`SimpleProxy`执行操作,然后在`RealObject`上调用相同的方法。
1469+
1470+
当你希望将额外的操作与“真实对象”做分离时,代理可能会有所帮助,尤其是当你想要轻松地启用额外的操作时,反之亦然(设计模式就是封装变更---所以你必须改变一些东西以证明模式的合理性)。例如,如果你想跟踪对`RealObject`中方法的调用,或衡量此类调用的开销,该怎么办?这不是你要写入到程序中的代码,而且代理使你可以很轻松地添加或删除它。
1471+
1472+
Java的*动态代理*更进一步,不仅动态创建代理对象而且动态处理对代理方法的调用。在动态代理上进行的所有调用都被重定向到单个*调用处理程序*,该处理程序负责发现调用的内容并决定如何处理。这是`SimpleProxyDemo.java`使用动态代理重写的例子:
1473+
1474+
```java
1475+
// typeinfo/SimpleDynamicProxy.java
1476+
import java.lang.reflect.*;
1477+
1478+
class DynamicProxyHandler implements InvocationHandler {
1479+
private Object proxied;
1480+
DynamicProxyHandler(Object proxied) {
1481+
this.proxied = proxied;
1482+
}
1483+
@Override
1484+
public Object
1485+
invoke(Object proxy, Method method, Object[] args)
1486+
throws Throwable {
1487+
System.out.println(
1488+
"**** proxy: " + proxy.getClass() +
1489+
", method: " + method + ", args: " + args);
1490+
if(args != null)
1491+
for(Object arg : args)
1492+
System.out.println(" " + arg);
1493+
return method.invoke(proxied, args);
1494+
}
1495+
}
1496+
1497+
class SimpleDynamicProxy {
1498+
public static void consumer(Interface iface) {
1499+
iface.doSomething();
1500+
iface.somethingElse("bonobo");
1501+
}
1502+
public static void main(String[] args) {
1503+
RealObject real = new RealObject();
1504+
consumer(real);
1505+
// Insert a proxy and call again:
1506+
Interface proxy = (Interface)Proxy.newProxyInstance(
1507+
Interface.class.getClassLoader(),
1508+
new Class,
1509+
new DynamicProxyHandler(real));
1510+
consumer(proxy);
1511+
}
1512+
}
1513+
/* Output:
1514+
doSomething
1515+
somethingElse bonobo
1516+
**** proxy: class $Proxy0, method: public abstract void
1517+
Interface.doSomething(), args: null
1518+
doSomething
1519+
**** proxy: class $Proxy0, method: public abstract void
1520+
Interface.somethingElse(java.lang.String), args:
1521+
[Ljava.lang.Object;@6bc7c054
1522+
bonobo
1523+
somethingElse bonobo
1524+
*/
1525+
```
1526+
1527+
可以通过调用静态方法`Proxy.newProxyInstance()`来创建动态代理,该方法需要一个类加载器(通常可以从已加载的对象中获取),希望代理实现的接口列表(不是类或抽象类),以及接口`InvocationHandler`的一个实现。动态代理会将所有调用重定向到调用处理程序,因此通常为调用处理程序的构造函数提供对“真实”对象的引用,以便一旦执行中介任务便可以转发请求。
1528+
1529+
`invoke()`方法被传递给代理对象,以防万一你必须区分请求的来源---但是在很多情况下都无需关心。但是,在`invoke()`内的代理上调用方法时要小心,因为通过接口的调用是通过代理重定向的。
1530+
1531+
通常执行代理操作,然后使用`Method.invoke()`传递必要的参数将请求转发给代理对象。这在一开始看起来是有限制的,好像你只能执行一般的操作。但是,可以过滤某些方法调用,同时传递其他方法调用:
1532+
1533+
```java
1534+
// typeinfo/SelectingMethods.java
1535+
// Looking for particular methods in a dynamic proxy
1536+
import java.lang.reflect.*;
1537+
1538+
class MethodSelector implements InvocationHandler {
1539+
private Object proxied;
1540+
MethodSelector(Object proxied) {
1541+
this.proxied = proxied;
1542+
}
1543+
@Override
1544+
public Object
1545+
invoke(Object proxy, Method method, Object[] args)
1546+
throws Throwable {
1547+
if(method.getName().equals("interesting"))
1548+
System.out.println(
1549+
"Proxy detected the interesting method");
1550+
return method.invoke(proxied, args);
1551+
}
1552+
}
1553+
1554+
interface SomeMethods {
1555+
void boring1();
1556+
void boring2();
1557+
void interesting(String arg);
1558+
void boring3();
1559+
}
1560+
1561+
class Implementation implements SomeMethods {
1562+
@Override
1563+
public void boring1() {
1564+
System.out.println("boring1");
1565+
}
1566+
@Override
1567+
public void boring2() {
1568+
System.out.println("boring2");
1569+
}
1570+
@Override
1571+
public void interesting(String arg) {
1572+
System.out.println("interesting " + arg);
1573+
}
1574+
@Override
1575+
public void boring3() {
1576+
System.out.println("boring3");
1577+
}
1578+
}
1579+
1580+
class SelectingMethods {
1581+
public static void main(String[] args) {
1582+
SomeMethods proxy =
1583+
(SomeMethods)Proxy.newProxyInstance(
1584+
SomeMethods.class.getClassLoader(),
1585+
new Class,
1586+
new MethodSelector(new Implementation()));
1587+
proxy.boring1();
1588+
proxy.boring2();
1589+
proxy.interesting("bonobo");
1590+
proxy.boring3();
1591+
}
1592+
}
1593+
/* Output:
1594+
boring1
1595+
boring2
1596+
Proxy detected the interesting method
1597+
interesting bonobo
1598+
boring3
1599+
*/
1600+
```
1601+
1602+
在这个示例里,我们只是在寻找方法名,但是你也可以寻找方法签名的其他方面,甚至可以搜索特定的参数值。
1603+
1604+
动态代理不是你每天都会使用的工具,但是它可以很好地解决某些类型的问题。你可以在Erich Gamma等人的*设计模式*中了解有关*代理*和其他设计模式的更多信息。 (Addison-Wesley1995年),以及[设计模式](./25-Patterns.md)一章。
14081605

14091606
<!-- Using Optional -->
14101607
## Optional

0 commit comments

Comments
 (0)