interface Image { public void displayImage(); }
class RealImage implements Image { private String filename; public RealImage(String filename) { this.filename = filename; loadImageFromDisk(); }
private void loadImageFromDisk() { System.out.println("Loading " + filename); }
public void displayImage() { System.out.println("Displaying " + filename); } }
class ProxyImage implements Image { private String filename; private Image image;
public ProxyImage(String filename) { this.filename = filename; } public void displayImage() { if(image == null) image = new RealImage(filename); image.displayImage(); } }
class ProxyExample { public static void main(String[] args) { Image image = new ProxyImage("MyPhoto"); image.displayImage(); } } |
运行结果:
与装饰模式的区别:
装饰模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。换句话 说,用代理模式,代理类可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们通常在一个代理类中创建一个对象的实例。当我们使用装饰器模式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。使用代理模式,代理和真实对象之间的的关系通常在编译时就已经确定了,而装饰者能够在运行时递归地被构造,例如:
//蓝莓冰淇淋 |
在Guava的TimeLimiter类中就应用到了代理模式:
TimeLimiter:用于对某一类对象的所有方法运行时间进行限制,即在给定时限内方法正常执行,否则抛出异常。该类生成一个代理,当调用被代理的对象的方法时,会强制加一个时间限制。定义了 newProxy(T target, Class<T> interfaceType, long timeoutDuration, TimeUnit timeoutUnit) 和 callWithTimeOut(Callable<T> callable, long timeoutDuration, TimeUnit timeoutUnit, boolean interruptible)。
1、 newProxy()方法生成 target的一个代理
注意:参数interfaceType必须为接口类型。
在该方法中,首先会找出接口的interruptible方法:
Set<Method> set = Sets.newHashSet();
for (Method m : interfaceType.getMethods()) {
if (declaresInterruptedEx(m)) {
set.add(m);
}
}
|
这里会判断接口的每一个方法是否抛出InterruptedException异常,如果没有抛出,则不会加到interruptible方法集合里。
例如上面得到的Method集合为:
在调用callWithTimeout时, 该集合用来判断,调用的方法是否amInterruptible。
以判断应该调用future.get(timeoutDuration, timeoutUnit); 或 Uninterruptibles.getUninterruptibly(future, timeoutDuration, timeoutUnit);来获取执行结果。
下面例子中,将直接使用上面代理模式中定义的类:
TimeLimiter limiter = new SimpleTimeLimiter();
Image image = new
ProxyImage("MyPhoto");
Image proxy = limiter.newProxy(image, Image.class, 1000, TimeUnit.MILLISECONDS);
try {
proxy.displayImage();
} catch (Exception e) {
e.printStackTrace();
}
|
运行结果:
2、 callWithTimeout() 方法:如果 callable执行完毕时还没有到达限定时间则将结果或异常传给调用者,否则抛出 UncheckedTimeoutException。用法如下:
public class TimeLimiterTest {
public static void main(String[] args){
SimpleTimeLimiter simpleTimeLimiter = new SimpleTimeLimiter();
String hello = null;
try {
hello = simpleTimeLimiter.
callWithTimeout(new Callable<String>(){
@Override
public String call() throws Exception {
return "Hello";
}
}, 100, TimeUnit.MILLISECONDS, true);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(hello);
String word = null;
try {
word = simpleTimeLimiter.
callWithTimeout(new Callable<String>(){
@Override
public String call() throws Exception {
Thread.sleep(
100);
return "Word";
}
},
99, TimeUnit.MILLISECONDS, true);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(word);
}
}
|
结果:运行超时