代理模式
静态代理
【角色分析】
- 抽象角色:一般会使用【接口/抽象类】解决
- 真实角色:被代理角色
- 代理角色:代理真实角色,代理后一般会做一些附属操作
- 客户:访问代理对象的人
【代码步骤】
- 接口
package cn.iris.demo01;
/**
* @author Iris 2021/8/12
*/
// 租房
public interface Rent {
public void rent();
}
- 真实角色
package cn.iris.demo01;
/**
* @author Iris 2021/8/12
*/
// 房东
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房东出租房子...");
}
}
- 代理角色
package cn.iris.demo01;
/**
* @author Iris 2021/8/12
*/
public class Proxy implements Rent{
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
visitHouse();
fare();
sign();
host.rent();
}
/**
* 看房
*/
public void visitHouse() {
System.out.println("中介带你看房...");
}
/**
* 收中介费
*/
public void fare() {
System.out.println("中介收你钱...");
}
/**
* 签合同
*/
public void sign() {
System.out.println("中介和你签租赁合同...");
}
}
- 客户端访问代理角色
package cn.iris.demo01;
/**
* @author Iris 2021/8/12
*/
public class Client {
public static void main(String[] args) {
// 房东:想租房子
Host host = new Host();
// 代理:中介帮房东租房子,同时增加附属操作
Proxy proxy = new Proxy(host);
// 用户:不用找房东,直接接触中介租房子
proxy.rent();
}
}
【代理模式的好处】
- 使真实角色的操作更加纯粹,不用关注一些公共业务
- 公共业务交予代理角色负责,实现了业务分工
- 公共业务扩展时,方便集中管理
- 在项目中可避免对原业务代码进行修改而导致项目崩溃【避免了‘刨祖坟’(狗头)】
【缺点】
- 一个真实角色会产生一个代理角色,多个真实角色会产生大量代码,降低开发效率
动态代理
- 动态代理与静态代理中的角色相同
- 动态代理的代理类动态生成
- 动态代理分为两类:基于接口的动态代理,基于类的动态代理
- 基于接口的动态代理---JDK动态代理
- 基于类的动态代理---cglib
- Java字节码实现:javassist(JBoss服务器)
需要了解两个了:Proxy,InvocationHandler(调用处理程序)
【代码实现】
package cn.iris.demo02;
/**
* @author Iris 2021/8/12
*/
public interface UserService {
void add();
void del();
void update();
void query();
}
package cn.iris.demo02;
/**
* @author Iris 2021/8/12
*/
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加一个用户");
}
@Override
public void del() {
System.out.println("删除一个用户");
}
@Override
public void update() {
System.out.println("更新一个用户");
}
@Override
public void query() {
System.out.println("查询一个用户");
}
}
package cn.iris.demo04;
import cn.iris.demo03.Rent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 使用该类动态生成代理类
* @author Iris 2021/8/12
*/
public class ProxyInvocationHandler implements InvocationHandler {
/**
* 被代理接口
*/
private Object target;
public void setTarget(Object target) {
this.target = target;
}
/**
* 生成得到代理类
* @return
*/
public Object getProxy() {
return Proxy.newProxyInstance(
this.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
/**
* 处理代理实例并返回结果
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 动态代理本质:使用【反射机制】实现
log(method.getName());
Object res = method.invoke(target, args);
return res;
}
public void log(String msg) {
System.out.println("使用了"+msg+"方法");
}
}
package cn.iris.demo04;
import cn.iris.demo02.UserService;
import cn.iris.demo02.UserServiceImpl;
/**
* @author Iris 2021/8/12
*/
public class Client {
public static void main(String[] args) {
// 真实角色
UserServiceImpl userService = new UserServiceImpl();
// 代理角色(不存在)
ProxyInvocationHandler pih = new ProxyInvocationHandler();
// 设置要代理的对象
pih.setTarget(userService);
// 动态生成代理类
UserService proxy = (UserService) pih.getProxy();
proxy.add();
proxy.del();
proxy.update();
proxy.query();
}
}
【动态代理的好处】
- 静态代理的所有好处
- 一个动态代理类代理的是一个接口,即是对应的一类业务
- 一个动态代理类可以代理多个类,只要实现了同一个接口