所谓代理模式,就相当于我们生活中的代理一样,比如说,我们要去租赁一个房子,直接找房东是不容易的,一般我们会找一个中介,也就是代理,来租房子,这个中介不仅能把房东的房子租给我们,而且可以带我们看房子等操作
当我们完成一个租房这件事时,实际上需要参与的有三个人,分别是租房者、中介和房东
静态代理
通过静态代理我们来实现中通过中介来出租房子,这里首先定一个出租房子的接口
package com.zhiying.demo01;
public interface Rent {
public void rent();
}
然后房东来实现这个接口
package com.zhiying.demo01;
public class Host implements Rent {
public void rent() {
System.out.println("房东出租房子");
}
}
中介也就是代理也要实现这个接口,主要是来棒房东出租房子
package com.zhiying.demo01;
public class Proxy implements Rent{
private Host host;
public void setHost(Host host) {
this.host = host;
}
public void rent() {
//这里是代理帮助房东出租房子
host.rent();
}
}
然后是客户类
package com.zhiying.demo01;
public class Client {
public static void main(String[] args) {
Host host = new Host();
Proxy proxy = new Proxy();
proxy.setHost(host);
proxy.rent();
}
}
客户通过代理租到了房子,这样做的好处是,当我们有新的工作要做的时候,我们只要找代理就可以了,而无须找房东,假如我们这里新增看房子和签合同的事情,这里只需代理完成即可,房东还只是出租房子。这里给出修改后的代理类,其他的不变
package com.zhiying.demo01;
public class Proxy implements Rent{
private Host host;
public void setHost(Host host) {
this.host = host;
}
public void rent() {
//这里是代理帮助房东出租房子
host.rent();
seeHost();
seeHost();
}
public void seeHost() {
System.out.println("代理带你看房子");
}
public void signContract() {
System.out.println("代理跟你签合同");
}
}
再来一个例子进行深刻理解代理模式,这里以完成CRUD业务来讲解,通过代理进行业务的扩展案例,首先是正常的业务,也就是单纯的CRUD,并且是没有代理的情况
业务的接口
package com.zhiying.demo02;
public interface Service {
public void add();
public void delete();
public void update();
public void select();
}
业务的实现
package com.zhiying.demo02;
import javax.xml.bind.SchemaOutputResolver;
public class ServiceImpl implements Service {
public void add() {
System.out.println("add");
}
public void delete() {
System.out.println("delete");
}
public void update() {
System.out.println("update");
}
public void select() {
System.out.println("select");
}
}
客户端
package com.zhiying.demo02;
public class Client {
public static void main(String[] args) {
ServiceImpl service = new ServiceImpl();
service.add();
service.delete();
service.update();
service.select();
}
}
这样是没有任何问题的,但是当我们进行扩展的时候,就需要代理来完成了,假如我们想要在每次执行CRUD之前,输出一个log,由于我们不能改原有的代码,这也符合开闭原则,引入代理
这里新增一个代理类
package com.zhiying.demo02;
public class Proxy implements Service {
ServiceImpl service;
public void setService(ServiceImpl service) {
this.service = service;
}
public void add() {
log("add");
service.add();
}
public void delete() {
log("delete");
service.delete();
}
public void update() {
log("update");
service.update();
}
public void select() {
log("select");
service.select();
}
public void log(String msg) {
System.out.println("this is " + msg);
}
}
客户端类在调用的时候直接调用代理类,其他类不用动
package com.zhiying.demo02;
public class Client {
public static void main(String[] args) {
ServiceImpl service = new ServiceImpl();
Proxy proxy = new Proxy();
proxy.setService(service);
proxy.add();
proxy.delete();
proxy.update();
proxy.select();
}
}
小结:代理模式可以使真实角色(房东)的工作更加纯粹,不用去关注一些公共的业务,公共的业务交给代理来做,实现了业务分工,公共业务发生扩展的时候,方便集中管理。
缺点:每一个真是的角色都会产生一个代理角色,代码量会翻倍,开发效率会降低
为解决这一问题,引入了动态代理,其中动态代理分为两大类,其一是基于接口的JDK提供,其二是基于类的cglib,这里讲解基于接口的
动态代理
JDK提供的类需要了解这两个,分别是,Proxy:代理 InvocationHandler:调用处理程序,同样的我们以租房子为例
出租房子接口
package com.zhiying.demo03;
public interface Rent {
public void rent();
}
房东类
package com.zhiying.demo03;
public class Host implements Rent {
public void rent() {
System.out.println("房东出租房子");
}
}
动态生成代理类
package com.zhiying.demo03;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//该类会自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler{
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
//处理代理程序,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质,用反射机制
seeHost();//被扩展的功能可以直接加到这
Object result = method.invoke(rent,args);
return result;
}
//在这里可以扩展功能
public void seeHost() {
System.out.println("代理带看房子");
}
}
客户类
package com.zhiying.demo03;
import com.sun.org.apache.regexp.internal.RE;
public class Client {
public static void main(String[] args) {
//这是真实角色,也就是我们的房东
Host host = new Host();
//创建代理调用处理角色
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
//通过调用程序处理角色来处理我们要调用的接口对象
proxyInvocationHandler.setRent(host);
//创建代理对象
Rent proxy = (Rent) proxyInvocationHandler.getProxy();
proxy.rent();
}
}
CRUD业务用动态代理实现
首先是业务接口
package com.zhiying.demo04;
public interface Service {
public void add();
public void delete();
public void update();
public void select();
}
然后是接口的实现
package com.zhiying.demo04;
public class ServiceImpl implements Service {
public void add() {
System.out.println("add");
}
public void delete() {
System.out.println("delete");
}
public void update() {
System.out.println("update");
}
public void select() {
System.out.println("select");
}
}
然后是动态生成代理类
package com.zhiying.demo04;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
Service service;
public void setService(Service service) {
this.service = service;
}
//生成代理类
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),service.getClass().getInterfaces(),this);
}
//处理代理类,返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());//调用扩展业务
Object result = method.invoke(service,args);
return result;
}
//增加的扩展业务
public void log(String msg) {
System.out.println("this is " + msg);
}
}
最后是我们的客户
package com.zhiying.demo04;
public class Client {
public static void main(String[] args) {
//创建真实角色,也就是我们的业务
ServiceImpl service = new ServiceImpl();
//创建代理调用处理角色
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
//设置要代理的对象
proxyInvocationHandler.setService(service);
//动态生成代理类
Service proxy = (Service) proxyInvocationHandler.getProxy();
proxy.add();
proxy.delete();
proxy.update();
proxy.select();
}
}
总结动态代理类的好处:首先有静态代理类的全部好处
代理模式可以使真实角色(房东)的工作更加纯粹,不用去关注一些公共的业务
公共的业务交给代理来做,实现了业务分工
公共业务发生扩展的时候,方便集中管理
一个动态代理类代理的是一个接口,一般就是对应一类的业务
一个动态代理类可以代理多个类,只要实现了同一个接口