代理模式:通过代理,控制对对象的访问。
它的设计思路是:定义一个抽象角色,让代理角色和真实角色分别去实现它。
代理模式分为静态代理和动态代理。
静态代理:歌星接口(SingerStar),一个歌星(Singer),歌星对应的代理(ProxyStar)。歌星和代理实现歌星接口里的sing()方法,代理ProxyStar在sing()中调用Singer.sing()完成真是的动作唱歌,在Singer.sing()前后加入处理。
/**
* 歌星接口
* @author lenovo
*
*/
public interface SingStar {
public void sing();
}
/**
* XX歌星
* @author lenovo
*
*/
public class Singer implements SingStar {
private String song;
public Singer ( ) {
}
public Singer (String song) {
this.song = song;
}
@Override
public void sing() {
System.out.println("歌手唱歌"+song);
}
}
/**
* XX歌星代理
* @author lenovo
*
*/
public class ProxyStar implements SingStar {
/**
* 真实角色
*/
private SingStar realStar;
public ProxyStar (SingStar realStar) {
this.realStar = realStar;
}
@Override
public void sing() {
System.out.println("唱歌之前的谈判...");
this.realStar.sing();
System.out.println("唱完歌后的事务处理...");
}
}
/**
* 测试
* @author lenovo
*
*/
public class Client {
public static void main(String[] args) {
Singer singer = new Singer("下雪啦");
ProxyStar proxyStar = new ProxyStar(singer);
proxyStar.sing();
}
}
运行结果:
唱歌之前的谈判...
歌手唱歌下雪啦
唱完歌后的事务处理...
动态代理:与静态代理相比建,动态代理的代理类是动态生成的,可以根据不同的接口生成不同的代理类,适用范围更加广泛。
/**
* 歌星接口
* @author lenovo
*
*/
public interface SingStar {
public void sing();
}
/**
* XX歌星
* @author lenovo
*
*/
public class Singer implements SingStar {
private String song;
public Singer ( ) {
}
public Singer (String song) {
this.song = song;
}
@Override
public void sing() {
System.out.println("歌手唱歌"+song);
}
}
/**
* 舞星接口
* @author lenovo
*
*/
public interface DanceStar {
public void dance (String name);
}
/**
* XX舞星
* @author lenovo
*
*/
public class Dancer implements DanceStar {
@Override
public void dance(String name ) {
System.out.println("舞星开始跳舞:" +name);
}
}
/**
* 生成动态代理类
* @author lenovo
*
*/
public class DynamicProxy {
/**
* @param realObj 需要被代码的对象
* @return 生成的代理对象
* 使用final的原因:匿名内部类中使用了外部参数,不允许修改外部参数
*/
public Object getDynamicProxy(final Object realObj){
return Proxy.newProxyInstance(realObj.getClass().getClassLoader(),
realObj.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (("sing").equals(method.getName())) {
System.out.println("代理谈价钱安排唱歌");
method.invoke(realObj, args);
System.out.println("代理在明星唱完歌后收钱");
}
if (("dance").equals(method.getName())) {
System.out.println("代理谈价钱安排跳舞");
method.invoke(realObj, args);
System.out.println("代理在明星跳舞后收钱");
}
return null;
}
});
}
}
/**
* 测试
* @author lenovo
*
*/
public class Client {
public static void main(String[] args) {
Singer singer = new Singer("下雪啦");
SingStar dynamicProxy = (SingStar) new DynamicProxy().getDynamicProxy(singer);
dynamicProxy.sing();
Dancer dancer = new Dancer();
DanceStar danceStarProxy = (DanceStar) new DynamicProxy().getDynamicProxy(dancer);
danceStarProxy.dance("Jump");
}
}
运行结果:
代理谈价钱安排唱歌
歌手唱歌下雪啦
代理在明星唱完歌后收钱
代理谈价钱安排跳舞
舞星开始跳舞:Jump
代理在明星跳舞后收钱
JDK:JDK 实现动态代理需要实现类通过接口定义业务方法。意味着代理类只能控制到接口中的方法。
CGLIB:对于没有接口的类可采用CGLIB实现动态代码,但是因为采用的是继承,所以final修饰的类是不能动态代理的。