面试:你懂什么是分布式系统吗?Redis分布式锁都不会?>>>
简介
即Proxy Pattern,23种java常用设计模式之一。 代理模式的定义:给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
代理模式的主要作用有两点:
1. 因为某些原因一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
Q: 何为“不想或者不能直接引用另一个对象”?
A: 如果执行某个操作需要进行远程调用网络另一端的计算机,如果不使用代理模式,则需要将复杂的网络通信部分硬编码入客户端。为了简化客户端的行为,可以使用代理模式,由客户端通过代理对象向远程的计算机发出指令,网络通信部分则有代理对象完成。
2. 在代理对象调用被代理对象的方法前后,可以附加一些额外的操作(如对数据加密)。
代理的种类
如果按照使用的目的类划分,代理有以下几种:
1:远程(remote)代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间可以是本机器中,也可以是另外一台机器中.
2:虚拟(Virtual)代理:根据需要创建一个资源消耗较大的对象,使的此对象只在需要时才会本真正创建。例如,连接网络,加载图片等操作。
3:copy——on-write代理:虚拟代理的一种,把复制(克隆)拖延到只有在客户端需要时,才真正采取行动。
4:保护(Protect or access)代理:控制对某个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限。
5:智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,
还有一些其他的代理,这里不再一一列举。
代理的结构:
类图如下:
抽象主题(Subject)角色:申明了真正主题和代理主题的公共接口,这样在任何可以使用真正主题的地方使用代理主题
代理(Proxy)主题角色: 代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真正主题对象,代理主题角色提供一个与真正主题角色相同的接口,以便可以在任 何时候都可以代替真正主题,负责在需要的是他创建真正主题对象(和删除真正主题对象);代理角色通常在客户端调用传递给真实的主题之前或之后,都要执行某些操作,而不是单纯的将调用传递给真正的对象。
真正主题角色:定义了代理角色所代表的真正对象
在分析一下代理模式时序图
例如:
抽象接口
public abstract class Subject {
abstract public void request();
}
真正主题角色:
public class RealSubject extends Subject {
@Override
public void request() {
// TODO Auto-generated method stub
System.out.println("from real subject");
}
}
代理角色
public class ProxySubject extends Subject {
private RealSubject realSubject;
@Override
public void request() {
preRequest();
if (realSubject == null) {
realSubject = new RealSubject();
}
realSubject.request();
postRequest();
}
private void preRequest() {
System.out.println("=======preRequest()========");
}
private void postRequest() {
System.out.println("=============postRequest()===========");
}
}
测试类
public class Main {
public static void main(String[] args) {
ProxySubject proxy=new ProxySubject();
proxy.request();
}
}
//
输出结果
=======preRequest()========
from real subject
=============postRequest()===========
二:动态代码
应用java中的反射机制,实现动态代理
下面是核心代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/***
* 动态代理对象
*
* @author gavin
*
*/
public class MyInvocationHandler implements InvocationHandler {
/**
* 因为需要处理真实角色,所以要把真实角色传进来
*/
Iinterface realSubject ;
public MyInvocationHandler(Iinterface realSubject) {
this.realSubject = realSubject;
}
/**
*
* @param proxy 代理类
* @param method 正在调用的方法
* @param args 方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("调用代理类");
if(method.getName().equals("sellBooks")){
// 返回值是真实代理方法的返回值
int invoke = (int)method.invoke(realSubject, args);
System.out.println("调用的是卖书的方法");
return invoke ;
}else {
String string = (String) method.invoke(realSubject,args) ;
System.out.println("调用的是说话的方法");
return string ;
}
}
}
抽象接口
public interface Iinterface {
public int sellBooks();
public String speak();
}
真实代码
public class RealSubject implements Iinterface{
@Override
public int sellBooks() {
System.out.println("卖书---RealSubject ");
return 1 ;
}
@Override
public String speak() {
System.out.println("说话----RealSubject");
return "张三";
}
}
测试类
public class Test {
public static void main(String[] args) {
test();
}
public static void test() {
try {
// 真实对象
Iinterface realSubject = new RealSubject();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(
realSubject);
// 代理对象
Iinterface proxyClass = (Iinterface) Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(),
new Class[] { Iinterface.class }, myInvocationHandler);
System.out.println("-------one---");
proxyClass.sellBooks();
System.out.println("-------two---");
proxyClass.speak();
} catch (Exception re) {
String ss = re.getMessage();
System.out.print(ss); // 真实对象
}
}
}
运行结果
-------one---
调用代理类
卖书
调用的是卖书的方法
-------two---
调用代理类
说话
调用的是说话的方法