代理模式
动态代理
- 想将额外的操作从实际对象分离,可以通过代理去调用对象,通过是否使用代理对对象进行操作,决定是否要进行一些额外操作
- 动态代理允许在运行时创建一个符合某些给定接口的代理对象,此对象可以在调用实际方法前后执行特定操作。
interface Interface {
void doSomething();
void somethingElse(String arg);
}
class RealObject implements Interface {
@Override public void doSomething() {
System.out.println("doSomething");
}
@Override public void somethingElse(String arg) {
System.out.println("somethingElse " + arg);
}
}
class DynamicProxyHandler implements InvocationHandler {
private Object proxied;
DynamicProxyHandler(Object proxied) {
this.proxied = proxied;
}
//任何通过代理对象发起的方法调用都会被转发到这个接口的 invoke 方法。
@Override public Object
invoke(Object proxy, Method method, Object [] args)
throws Throwable {
System.out.println(
"**** proxy: " + proxy.getClass() +
", method: " + method + ", args: " + args);
if(args != null)
for(Object arg : args)
System.out.println(" " + arg);
return method.invoke(proxied, args);
}
}
class SimpleDynamicProxy {
public static void consumer(Interface iface) {
iface.doSomething();
iface.somethingElse("bonobo");
}
public static void main(String [] args) {
RealObject real = new RealObject();
consumer(real);
// 创建动态代理(在运行时动态创建一个实现了指定接口的代理对象)
Interface proxy = (Interface)Proxy.newProxyInstance(
Interface.class.getClassLoader(),
new Class []{ Interface.class },//会被代理的接口(方法),可以有多个
new DynamicProxyHandler(real));
//得到了一个代理对象
consumer(proxy);
}
}
Proxy.newProxyInstance
需要三个参数:类加载器、一组接口以及一个 InvocationHandler
实例。
import java.lang.reflect.*;
// Step 1: Define interfaces
interface Interface1 {
void doSomething();
}
interface Interface2 {
void doSomethingElse();
}
// Step 2: Create implementations
class Implementation1 implements Interface1 {
public void doSomething() {
System.out.println("Implementation1 doing something");
}
}
class Implementation2 implements Interface2 {
public void doSomethingElse() {
System.out.println("Implementation2 doing something else");
}
}
// Step 3: Create dynamic proxy
class MixinProxy implements InvocationHandler {
private final Object [] delegates;
public MixinProxy(Object... delegates) {
this.delegates = delegates;
}
public Object invoke(Object proxy, Method method, Object [] args) throws Throwable {
for (Object delegate : delegates) {
if (method.isInstance(delegate)) {
return method.invoke(delegate, args);
}
}
throw new UnsupportedOperationException("Method not supported: " + method);
}
//帮助创建动态代理
@SuppressWarnings("unchecked")
public static <T> T createMixinProxy(Class <T> interfaceClass, Object... delegates) {
//取出传入对象的类型
Class <?> [] interfaces = new Class <?> [delegates.length];
//存储接口
for (int i = 0; i < delegates.length; i++) {
interfaces [i] = delegates [i].getClass().getInterfaces()[0];
}
return (T) Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
interfaces,
new MixinProxy(delegates)
);
}
}
// Using the mixin
public class MixinDemo {
public static void main(String [] args) {
Object mixin = MixinProxy.createMixinProxy(Object.class, new Implementation1(), new Implementation2());
//还需要手动转换类型
Interface1 if1 = (Interface1) mixin;
Interface2 if2 = (Interface2) mixin;
if1.doSomething();
if2.doSomethingElse();
}
}
标签接口
- 标签接口是没有定义任何方法的接口。标签接口的主要作用是为实现该接口的类提供一个特定的标识。这个标识允许类在运行时表现出一些特殊的行为。
class NullRobotProxyHandler
implements InvocationHandler {
private String nullName;
private Robot proxied = new NRobot();
NullRobotProxyHandler(Class <? extends Robot> type) {
//区分不同 Robot 子类的 Null 对象
nullName = type.getSimpleName() + " NullRobot";
}
//NULL 就是一个标签接口
private class NRobot implements Null, Robot {
@Override
public String name() { return nullName; }
@Override
public String model() { return nullName; }
@Override public List <Operation> operations() {
return Collections.emptyList();
}
}
//传递操作
@Override public Object
invoke(Object proxy, Method method, Object [] args)
throws Throwable {
return method.invoke(proxied, args);
}
}
public class NullRobot {
//通过代理创建具有空标签的对象
public static Robot
newNullRobot(Class <? extends Robot> type) {
return (Robot)Proxy.newProxyInstance(
NullRobot.class.getClassLoader(),
new Class []{ Null.class, Robot.class },
new NullRobotProxyHandler(type));
}
public static void main(String [] args) {
Stream.of(
new SnowRobot("SnowBee"),
newNullRobot(SnowRobot.class)
).forEach(Robot:: test);
}
}
- 使用代理的提供一种通用的方式来创建任何类型的
Robot
的空对象,而不需要为每个Robot
子类都创建一个特定的空对象类。
- 通过使用代理,你可以为任何
Robot
子类创建一个空对象,而不需要写任何额外的代码。这是因为代理对象的所有方法调用都会被转发给NullRobotProxyHandler
对象,然后由这个对象的invoke
方法处理。这个方法将方法调用转发给NRobot
对象,这个对象的所有方法都返回一个无操作的结果。