设计模式—静态代理模式(聚合与继承方式比较)

代理模式:

为某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。

静态代理模式:

由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

一、概述

1.目标:要在Tank的move()方法做时间代理及日志代理(可以设想以后还要增加很多代理处理),且代理间的顺序可活更换

2.思路:

(1)聚合:代理类聚合了被代理类,且代理类及被代理类都实现了movable接口,则可实现灵活多变,具体看代码

(2)继承:继承不够灵活,随着功能需求增多,继承体系会非常臃肿。具体看代码

 

二、代码

1.Movable.java

2.Tank.java

3.TankTimeProxy.java

4.TankLogProxy.java

5.Tank2Time.java

6.Tank3Log.java

7.Client.java

 

1.Movable.java

1 public interface Movable {
2     public void move();
3 }

 

2.Tank.java

复制代码
 1 import java.util.Random;
 2 
 3 public class Tank implements Movable {
 4 
 5     @Override
 6     public void move() {
 7         System.out.println("Tank moving.......");
 8         try {
 9             Thread.sleep(new Random().nextInt(5000));
10         } catch (InterruptedException e) {
11             e.printStackTrace();
12         }
13     }
14 
15 }
复制代码

 

3.TankTimeProxy.java

复制代码
 1 public class TankTimeProxy implements Movable {
 2 
 3     Movable m;
 4     
 5     public TankTimeProxy(Movable m) {
 6         this.m = m;
 7     }
 8 
 9     @Override
10     public void move() {
11         System.out.println("Time Proxy start...........");
12         long start = System.currentTimeMillis();
13         m.move();
14         long end = System.currentTimeMillis();
15         System.out.println("花费时间:"+(end - start));
16         System.out.println("Time Proxy end...........");
17     }
18 
19 }
复制代码

 

4.TankLogProxy.java

复制代码
 1 public class TankLogProxy implements Movable {
 2 
 3     Movable m;
 4     
 5     public TankLogProxy(Movable m) {
 6         this.m = m;
 7     }
 8 
 9     @Override
10     public void move() {
11         System.out.println("Log Proxy start...........");
12         m.move();
13         System.out.println("Log Proxy end...........");
14     }
15 
16 }
复制代码

 

5.Tank2Time.java

复制代码
 1 public class Tank2Time extends Tank {
 2 
 3     public void move(){
 4         System.out.println("Tank2 time  start...........");
 5         long start = System.currentTimeMillis();
 6         super.move();
 7         long end = System.currentTimeMillis();
 8         System.out.println("花费时间:"+(end - start));
 9         System.out.println("Tank2 time end...........");
10     }
11 }
复制代码

 

6.Tank3Log.java

复制代码
1 public class Tank3Log extends Tank2Time {
2 
3     public void move(){
4         System.out.println("Tank3Log  start...........");
5         super.move();
6         System.out.println("Tank3Log  end...........");
7     }
8 }
复制代码

 

7.Client.java

复制代码
 1 public class Client {
 2 
 3     @Test
 4     public void testProxy(){
 5         
 6         Tank t = new Tank();
 7         Movable m;
 8         
 9         //一、聚合的方式(较灵活,因为实现了接口)
10         //1.1聚合方式的代理,先日志代理,后时间代理
11         TankTimeProxy ttp1 = new TankTimeProxy(t);
12         TankLogProxy tlp1 = new TankLogProxy(ttp1);
13         
14         m = tlp1;
15         m.move();
16         
17         System.out.println("\n==============================分隔线==========================\n");
18         
19         //1.2聚合方式的代理,先时间代理,后日志代理(可以灵活切换顺序)
20         TankLogProxy tlp2 = new TankLogProxy(t);
21         TankTimeProxy ttp2 = new TankTimeProxy(tlp2);
22         
23         m = ttp2;
24         m.move();
25         
26         System.out.println("\n==============================分隔线==========================\n");
27         
28         //二、继承的方式
29         //2.1代理时间
30         Tank2Time t2 = new Tank2Time();
31         t2.move();
32         
33         System.out.println("\n==============================分隔线==========================\n");
34         
35         //2.2先代理日志,后时间,不能灵活切换
36         Tank3Log t3 = new Tank3Log();
37         t3.move(); 
41     }
42 }
复制代码

 

三、运行结果

 

因为每个代理都实现了同一movable接口,代理和被代理对象之间都可以相互灵活转换,以实现代理功能之间的灵活叠加组合。

 静态代理类优缺点
优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。
缺点:
1)代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。

2)如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

另外,如果要按照上述的方法使用代理模式,那么真实角色(委托类)必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色(委托类),该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。

posted @ 2017-05-17 17:47  开拖拉机的蜡笔小新  阅读(1616)  评论(1编辑  收藏  举报