java设计模式----代理模式
什么是代理模式?
代理模式的定义:对其他对象提供一种代理以控制对这个对象的访问—来自百度搜索
让我们用一种通俗的语言来理解下代理模式
抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
我还是举个例子来说明下,比如我去火车站买票这个例子
我就是被代理类,火车站就是代理类,我们需要明白一点,就是真正花钱买票的是我本人,而不是火车站,所以最后调用买票的方法是执行的被代理的方法,这个买票的方法,肯定是属于被代理类的,一句话就是被代理类有一个方法或者是接口,用来实现买票的功能
如果直接调用自己的方法去实现购票,谈何代理?所以接下来就分析下代理类-车站,我们调用车站的某个方法,其实本质上就是调用了我自己买票的方法,这里很关键,车站类里面肯定有一个我这个对象,为什么呢?因为车站调用某个方法是调用的我这个对象的方法,没有我这个对象,谈何调用?另外车站类里面,在随便定义一个方法,车站的方法里面在让我去调用自己的买票方法即可
来看下代码咯:
首先看下我这个人的一个接口方法,就是我买票的未实现的方法
package com.safly;
public interface MyInterface {
void myBuyTicket();
}
在来看看我这个本类,实现方法即可,我就输出一句话即可
package com.safly;
public class My implements MyInterface{
@Override
public void myBuyTicket() {
System.out.println("我买票");
}
}
接下来就看看代理类了,里面持有我一个引用,然后有随便一个方法,方法里面在调用我自己的方法即可
package com.safly;
public class Station {
public My my;
public Station(My my) {
super();
this.my = my;
}
public void stationBuyTicket(){
System.out.println("station buyTicket");
my.myBuyTicket();
}
}
看看主界面把
package com.safly;
public class MyMainUI {
public static void main(String[] args) {
Station station = new Station(new My());
station.stationBuyTicket();
}
}
输出如下:
station buyTicket
我买票
- 以上就是一个静态代理类,自己的买票方法,车站的一个方法,感觉2个方法名字不同,这样感觉不好,我们能不能同样实现一个相同的接口呢?就是同一个接口,这样看起来,效果更好,意思更明确,那我们就来改下把
package com.safly;
public interface MyInterface {
void myBuyTicket();
}
package com.safly;
public class My implements MyInterface{
@Override
public void myBuyTicket() {
System.out.println("我买票");
}
}
package com.safly;
public class Station implements MyInterface{
public My my;
public Station(My my) {
super();
this.my = my;
}
@Override
public void myBuyTicket() {
System.out.println("station buyTicket");
my.myBuyTicket();
}
}
package com.safly;
public class MyMainUI {
public static void main(String[] args) {
Station station = new Station(new My());
station.myBuyTicket();
}
}
输出log如下:
station buyTicket
我买票
以上就是静态代理,我们在来看下动态代理?
静态代理相对应动态代理有什么缺点呢?
如果上楼的例子里面,车站代理了我本人买票,如果在来一个人,他也要买票呢?车站需要在买票接口,去判断买票的人是谁吧?还得持有另外一个人的引用,这样设计起来,代码就会很臃肿,所以动态代理就为了解决这个问题,产生了。
(当然我是自己这样理解的,你还可以搜搜百度)
在Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 类的支持
,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用
//Object proxy:被代理的对象
//Method method:要调用的方法
//Object[] args:方法调用时所需要参数
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
代理类是通过Proxy.newProxyInstance得到一个动态的代理对象
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
以上3个参数的意思如下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
package com.safly;
public interface MyInterface {
void myBuyTicket();
}
package com.safly;
public class My implements MyInterface{
@Override
public void myBuyTicket() {
System.out.println("我买票");
}
}
package com.safly;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Station implements InvocationHandler {
/**
* 被代理对象targetObject通过参数传递进来,我们通过targetObject.getClass().getClassLoader()
* 获取ClassLoader对象,然后通过targetObject.getClass().getInterfaces()获取它实现的所有接口,
* 然后将targetObject包装到实现了InvocationHandler接口的LogHandler对象中
* 。通过newProxyInstance函数我们就获得了一个动态代理对象。
*/
private Object targetObject;
public Object newProxyInstance(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object arg0, Method method, Object[] arg2)
throws Throwable {
Object ret = null;
try {
System.out.println("satrt-->>");
// 调用目标方法
ret = method.invoke(targetObject, arg2);
System.out.println("success-->>");
} catch (Exception e) {
e.printStackTrace();
System.out.println("error-->>");
throw e;
}
return ret;
}
}
package com.safly;
public class MyMainUI {
public static void main(String[] args) {
Station station = new Station();
MyInterface myInterface = (MyInterface) station
.newProxyInstance(new My());
myInterface.myBuyTicket();
}
}
Log日志输出如下:
satrt-->>
我买票
success-->>
接下来,我们就修改修改参数等操作
My
package com.safly;
public class My implements MyInterface{
@Override
public void myBuyTicket(int money) {
System.out.println("我买票"+money);
}
}
MyInterface
package com.safly;
public interface MyInterface {
void myBuyTicket(int money);
}
Station
package com.safly;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Station implements InvocationHandler {
private Object targetObject;
Station(Object targetObject) {
this.targetObject = targetObject;
}
@Override
public Object invoke(Object arg0, Method method, Object[] arg2)
throws Throwable {
Object ret = null;
if ("myBuyTicket".equals(method.getName())) {
// 这里是代理Shopping接口的对象
// 先黑点钱(修改输入参数)
Integer money = (Integer) arg2[0];
Integer finalMoney = (Integer) (money * 2);
ret = method.invoke(targetObject, finalMoney);
// 帮忙买东西
}
return ret;
}
}
MyMainUI
package com.safly;
import java.lang.reflect.Proxy;
public class MyMainUI {
public static void main(String[] args) {
MyInterface my = new My();
my.myBuyTicket(100);
my = (MyInterface) Proxy.newProxyInstance(my.getClass()
.getClassLoader(), my.getClass().getInterfaces(), new Station(
my));
my.myBuyTicket(100);
}
}
输出如下:
我买票100
我买票200