代理模式
代理模式是一个很重要的模式,在平时使用和框架设计上用的比较多。
在Spring中AOP面向切片编程就使用了代理模式。
代理模式替代了真实对象的直接访问,我们可以在代理方法中做一些增强和补充。
代理模式的使用场景分为
- 安全代理,屏蔽对真实角色的直接访问
- 远程代理,通过代理类处理远程方法调用
- 延迟加载,先加载代理对象,然后按需加载真实对象
java代理模式的实现
java代理模式分为
- 静态代理
- 动态代理
- 接口动态代理
- 继承动态代理
静态代理的实现
首先代理类和真实类方法是一样的,肯定需要实现相同的接口
public interface Star {
void confer();
void signContract();
void sing();
void collectMoney();
}
然后代理类和真实类分别继承
真实类
public class RealStar implements Star {
@Override
public void confer() {
System.out.println("RealStar.confer");
}
@Override
public void signContract() {
System.out.println("RealStar.signContract");
}
@Override
public void sing() {
System.out.println("RealStar.sing");
}
@Override
public void collectMoney() {
System.out.println("RealStar.collectMoney");
}
}
代理类
public class ProxyStar implements Star {
private Star realStar;
public ProxyStar(Star realStar) {
this.realStar = realStar;
}
@Override
public void confer() {
System.out.println("ProxyStar.confer");
}
@Override
public void signContract() {
System.out.println("ProxyStar.signContract");
}
@Override
public void sing() {
realStar.sing();
}
@Override
public void collectMoney() {
System.out.println("ProxyStar.collectMoney");
}
}
注意代理类需要引用维护一个对应的真实对象
静态代理的实现还是很简单的
动态代理
动态代理十分的灵活高效,一般首选动态代理方法
JDK动态代理技术的性能在1.8之后已经很高了,大部分场合直接使用JDK原生技术即可,这里说明一下主要的使用方法
public class StarHandler implements InvocationHandler {
private Star realStar;
public StarHandler(Star realStar) {
this.realStar = realStar;
}
/**
* 使用了反射
*
* @param proxy 代理类
* @param method 正在调用的方法
* @param args 方法参数
* @return 函数调用返回的结果
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object result = method.invoke(realStar, args);
System.out.println("after");
return result;
}
}
public class ProxyClient {
public static void main(String[] args) {
Star star = new RealStar();
StarHandler starHandler = new StarHandler(star);
Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Star.class}, starHandler);
String sing = proxy.sing();
System.out.println(sing);
}
}
最后打印的结果为
before
RealStar.sing
after
sing very well
javascript的代理模式
es6中增加了Proxy的代理功能
const star = {
name:'张某某',
age:25,
phone:'13900001111'
}
const agent = new Proxy(star,{
get:function (target,key) {
if(key==='phone'){
return '13913012345'
}
if(key==='price'){
return 120000
}
return target[key]
},
set:function (target,key,val) {
if(key==='customPrice'){
if(val<100000){
throw new Error('price is low')
} else {
target[key] = val
return true //赋值成功
}
}
}
})
//请参照代理,不能直接访问原对象
console.log(agent.phone)
console.log(agent.price)
agent.customPrice = 120000
console.log(agent.customPrice)
和Object.defineProperty
功能是一样的,在vue3的版本中会使用Proxy
代替它