一、静态代理
我们平常去电影院看电影的时候,在电影开始的阶段是不是经常会放广告呢?
电影是电影公司委托给影院进行播放的,但是影院可以在播放电影的时候,产生一些自己的经济收益,比如卖爆米花、可乐等,然后在影片开始或者结束时插播一些广告。
接下来我们用代码进行模拟:
/*首先得有一个接口,通用的接口是代理模式实现的基础。这个接口我们命名为 Movie,代表电影播放的能力。*/ /*这里可以看做这是一个电影供应商,可以用来供应电影,这个电影可以用来播放,(你也可以定义说这个电影可以用来吃鸭)*/
package person.clp
public interface Movie {
void play();
//void eat();
}
下面是Movie接口的两个实现类:
/*这里看做电影供应商究竟供应了啥电影,比方说是《绿里奇迹》,比方说是《肖申克的救赎》,要给线下的电影院供应啥电影就在这里设置*/
/*如果供应商那里供应了电影可以用来吃的话,你这里就要实现它吃的方法咯,比如下面的eat方法*/
package person.clp
public class RealMovie implements Movie {
public void play() {
System.out.println("正在观看电影《肖申克的救赎》");
}
// public void eat(){
// System.out.println("油炸《肖申克的救赎》");
// }
}
/*这里是线下的电影院,用来实现播放供应商提供的电影,顺带可以做自己的事情*/
/*这里就是我们的代理类啦,代理了RealMovie这个类的播放功能*/
package person.clp
public class Cinema implements Movie {
RealMovie movie;//这里需要把电影供应商提供的电影传过来给它,不然不知道播放什么电影
//用一个构造函数去传值
public Cinema(RealMovie movie) {
this.movie = movie;
}
//这里是线下电影院自己可以做的事情,除了做做爆米花的广告之外还可以做其它的事,比方说卖女明星的原味内裤
public void sellPopcorn(){
System.out.println("演出马上开始了,爆米花一块钱一桶快来买啊!");
}
public void sellPanties(){
System.out.println("演出结束了,卖一下女主角的原味内裤当做纪念品,无限量供应!");
}
public void play() {//这里重写了Movie的play方法
sellPopcorn();//电影开始前卖爆米花
movie.play();//放电影,这里的movie是RealMovie传过来的
sellPanties();//电影结束卖内裤
}
}
编写我们的测试类:
package person.clp.test
public class ProxyTest {
public static void main(String[] args) {
RealMovie realmovie = new RealMovie();//这里new了一个要播放的电影(被代理类)
Movie movie = new Cinema(realmovie);//这里实现了一个线下的电影院(代理类)
movie.play();//线下电影院去播放
}
}
运行结果:
现在可以看到,代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。
二、动态代理
我们知道,电影院也可以发展副业的,有时候比方说我们剧院的舞台需要维修或者突然塌了被火烧了什么的,我们可以将演出地点改在电影院里面,可以边看跳舞边看电影,一举两得。
我们用代码来实现这个例子,先写一下跳舞的接口和舞台的实现类:
跳舞接口:
/*定义跳舞这个东西*/
package person.clp
public interface Dance {
void dancing();
}
舞台类:
/*我们让舞台这个类去实现Dance这个接口,就是在舞台上跳舞的意思,你也可以在厕所里面跳,写个厕所类去实现Dance这个接口*/
package person.clp
public class Stage implements Dance {
public void dancing() {
//我们这里在舞台上跳脱衣舞,也可以跳别的舞,肚皮舞啥的
System.out.println("在舞台上跳脱衣舞!");
}
}
来到这里,假设我们说舞台塌了,需要转移阵地去跳舞,然后转移到了电影院,
这里我们就需要通过编写一个代理类去实现Dance这个接口,然后去代理Stage里面的方法,假设我们的电影院是这个代理类:
package person.clp
public class Cinema implements Dance {
Stage stage;
//用一个构造函数去传值
public Cinema(Stage stage) {
this.stage = stage;
}
public void sellPopcorn(){
System.out.println("演出马上开始了,爆米花一块钱一桶快来买啊!");
}
public void sellPanties(){
System.out.println("演出结束了,卖一下女主角的原味内裤当做纪念品,无限量供应!");
}
public void dancing() {
sellPopcorn();
stage.dancing();//这里让电影院实现舞台的跳舞功能(代理舞台的跳舞功能)
sellPanties();
}
}
测试类:
package person.clp.test
public class ProxyTest {
public static void main(String[] args) {
Stage stage = new Stage();
Dance cinema = new Cinema(stage);
cinema.dancing();//在电影院里跳舞
}
}
运行结果:
好了,通过上面这个例子呢,我们发现静态代理模式一个很麻烦的就是,如果你现在有很多个需要被代理的类,你就要写很多个代理类去代理不同类的功能,这是一件很麻烦的一件事!
所以能不能不写这个代理类或者少写一点代理类的代码呢?我们希望能够有一个动态的代理类,在无论哪个类需要被代理的情况下,它都能作为一个代理类去代理这些需要被代理的类。
看起来有点绕,说白了就是只写一个代理类就能给全部人用呗,不用每个人都写一个代理,一个动态代理类就够代理它们全部了。
那怎么实现的呢?这里我们用到了反射机制!利用反射机制在运行时创建代理类!
看一下这个动态代理类:
package person.clp
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ProxyUtil implements InvocationHandler {
private Object object;
public ProxyUtil(Object object){
this.object = object;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(object, args);
return null;
}
}
然后我们通过这个动态代理类来测试一下原来的类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
Movie movie = new RealMovie();//这里被代理的是线下电影院
Dance dance = new Stage();//这里被代理的是舞台
InvocationHandler handler1 = new ProxyUtil(movie);
InvocationHandler handler2 = new ProxyUtil(dance);
Movie proxyMovie = (Movie) Proxy.newProxyInstance(movie.getClass().getClassLoader(), movie.getClass().getInterfaces(), handler1);
proxyMovie.play();
Dance proxyDance = (Dance) Proxy.newProxyInstance(dance.getClass().getClassLoader(), dance.getClass().getInterfaces(), handler2);
proxyDance.dancing();
}
}
运行结果:
这样我们就可以通过动态代理的方式在运行的时候去代理不同的类。实现边看电影边看脱衣舞!那不是一般的爽~
如果是静态代理的话,你要么就代理跳舞,要么就代理电影,而且还得改Cinema这个类里面的东西,如果不想改的话还得再写一个Cinema类,麻烦的很
这里通过动态代理的方式,你就可以一个代理类走天下了,无论以后说我电影院想发展副业,发展烧烤业,没事帮烧烤摊烤烤串,那么客人就可以边吃烧烤边看电影边跳脱衣舞
那你就直接写一个烧烤的接口,烧烤摊的实现类,然后用动态代理去代理它呗。少了好多好多代码素不素~