代码步骤
写代码我们有一个原则,多用组合少用继承
1、接口
//出租房屋
public interface Rent {
public void rent();
}
2、真实角色
//房东
public class Host implements Rent{
@Override
public void rent() {
System.out.println("我要租房子");
}
}
3、代理角色
//中介(代理者)
public class ProxyDaiLi implements Rent{
private Host host;
public ProxyDaiLi() {
}
public ProxyDaiLi(Host host) {
this.host = host;
}
@Override
public void rent() {
host.rent();
}
public void seeHost(){
System.out.println("中介带你去看房子");
}
public void HeTong(){
System.out.println("签合同");
}
}
4、客户端访问代理角色
//房客去租房(用户)
public class Client {
/**
* 写代码我们有一个原则,多用组合少用继承
* 客户端访问代理角色
*/
public static void main(String[] args) {
//组合真实的角色
Host host = new Host();
//代理
ProxyDaiLi proxyDaiLi = new ProxyDaiLi(host);
//代理角色一般都会有些附属操作,否则没有意义
proxyDaiLi.rent();
proxyDaiLi.HeTong();
}
}
运行结果如下:
一、代理模式的好处
- 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
- 公共的也就交给代理角色!实现业务的分工!
- 公共业务发生扩展的时候方便集中管理
二、缺点
- 一个真实的角色就会产生一个代理角色;代码量会翻倍,开发效率会变低
解决这个问题可以用动态代理
动态代理
- 动态代理和静态代理的角色是一样的(接口、真实角色、代理角色、用户访问代理角色)
- 动态代理的代理类是动态生成,不是我们直接写的
- 动态代理的风味两大类:基于接口的动态代理、基于累的动态代理
1.基于接口——JDK动态代理(我这里使用的是这种)
2.基于类:cglib
3.java字节码实现:Javasist(现在使用最多的)
了解:Proxy——代理、InvocationHandler——调用处理程序
代码步骤
1、接口
public interface Rent {
public void rent();
}
2、真实角色
public class Host implements Rent {
@Override
public void rent() {
System.out.println("我要租房子hahah hahahahah");
}
}
3、调用处理程序
package com.gzx.demo2;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* InvocationHandler:调用处理程序
* Invoke:要执行一个什么方法
*/
class ProxyInvocationHandler implements java.lang.reflect.InvocationHandler {
//被代理的的接口(用的是组合实现的)
private Rent rent;
public ProxyInvocationHandler() {
}
public void setRent(Rent rent){
this.rent = rent;
}
//这里是死的,只需改动rent的那个接口就可,生成得到的代理对象
public Object grtPoroxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(), this);
}
//处理代理的实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHose();
Object result = method.invoke(rent, args);
fare();
return null;
}
public void seeHose(){
System.out.println("中介到你去看房子哦!");
}
public void fare(){
System.out.println("收取中介费!!!");
}
}
4、用户访问动态代理
public class Client {
public static void main(String[] args) {
//实现真实角色
Host host = new Host();
//代理角色:
ProxyInvocationHandler proxyih = new ProxyInvocationHandler();
//通过调用程序角色来处理我们需要处理我们要调用的对象
proxyih.setRent(host);
//这里的proxy就是动态生成的,并没有去写
Rent proxy = (Rent) proxyih.grtPoroxy();
proxy.rent();
}
}
调试结果
动态代理改造
将步骤3进行改造,写成一个工具类
package com.gzx.demo3;
import com.gzx.demo2.Rent;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 工具类
* invocationHandler:调用处理程序
* invoke:要执行一个什么方法
*/
class ProxyInvocationHandler implements java.lang.reflect.InvocationHandler {
//被代理的的接口
private Object target;
public ProxyInvocationHandler(Object target) {
this.target = target;
}
public ProxyInvocationHandler() {
}
public void setTarget(Object target) {
this.target = target;
}
//生成的到代理类
public Object grtPoroxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
//处理代理的实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
public void log(String msg){
System.out.println("执行了"+msg+"方法");
}
}
用户访问动态代理
package com.gzx.demo3;
import com.gzx.demo.UserServiceImpl;
import com.gzx.demo.UserServuce;
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl();
//代理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//设置要生成的对象
pih.setTarget(userService);
//动态生成代理类
UserServuce poroxy = (UserServuce) pih.grtPoroxy();
poroxy.addUser();
}
}
运行结果