0%

代理模式

代理模式的应用场景:

  1. 一个对象不能直接访问另外一个对象的时候,我们可以通过访问该对象的代理对象去访问它。
  2. 在不修改类的源码的情况下,动态地增强类的方法,便于程序的扩展
  3. 动态地给接口创建代理对象,动态地实现接口中的方法
  4. 统一在方法执行之前做前置处理工作,在方法执行之后做后置处理工作,这样可以大大减少代码中的重复代码。这其实就是Spring中的AOP思想

面向对象设计有一个基本原则:开放封闭原则,对扩展开放对修改封闭

改变/增强一个方法,我们又哪些办法可以做到:

  1. 继承
  2. 装饰者模式:
    1. 装饰者和被装饰者要实现相同的接口
    2. 将被装饰者的对象传入到装饰者中
    3. 如果不需要增强的方法由被装饰者完成,装饰者只增强方法
  3. 代理模式:静态代理和动态代理
    1. 代理模式的组成部分:
      1. 代理者
      2. 委托者(被代理者)
      3. 接口
    2. 代理模式的特点:
      1. 代理者和委托者要实现相同的接口
      2. 将委托者的对象传入到代理者中
      3. 如果不需要增强的方法由委托者完成,代理者只增强方法

代理模式的分类:

  1. 静态代理模式:包含委托类、代理类以及统一的接口
  2. 动态代理模式:包含委托类和统一的接口,不包含代理类,而是使用反射机制在调用的时候动态生成代理对象

一.静态代理

1.Diagrams

decker

2.代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public interface IKindWomen {
void happy();
}

public class Jinlian implements IKindWomen {
@Override
public void happy() {
System.out.println("金莲正在happy...");
}
}

public class Wangpo implements IKindWomen {
//依赖倒置原则:依赖抽象不依赖具体,目的是增强程序的可扩展性
private IKindWomen women;

public Wangpo(Jinlian jinlian) {
this.women = jinlian;
}

@Override
public void happy() {
System.out.println("open room");
women.happy();
System.out.println("clear room");
}
}

@Test
public void test(){
Jinlian jinlian = new Jinlian();
Wangpo wangpo = new Wangpo(jinlian);
wangpo.happy();
}

二.动态代理

1.Diagrams

decker

2.代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public interface IKindWoman {
void happy();
double collect(double money);
}

public class Jinlian implements IKindWoman {
@Override
public void happy() {
System.out.println("金莲正在happy...");
}

@Override
public double collect(double money) {
System.out.println("金莲收款: " + money);
return money;
}
}

@Test
public void test(){
//访问金莲的happy方法
Jinlian jinlian = new Jinlian();

//使用动态代理技术生成代理对象
//Proxy.newProxyInstance()方法有三个参数:
// 1. 类加载器
// 2. 被代理者实现的所有接口的字节码对象
// 3. InvocationHandler接口的实现类对象

Class clazz = jinlian.getClass();
ClassLoader classLoader = clazz.getClassLoader();//获取类加载器
Class[] interfaces = clazz.getInterfaces();//委托者实现的所有接口

//Proxy.newProxyInstance(),方法的目的创建代理对象
//代理对象和委托对象肯定要实现相同的接口----IKindWomen
IKindWoman proxyInstance = (IKindWoman) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//代理者调用任何方法,都会执行invoke()
//所以在invoke()方法中编写代理规则
//invoke()方法的三个参数:1.proxy表示代理对象本身,我们不要去使用它,否则会发生死递归
//2. method表示,当前代理对象调用的那个方法 3. args表示当前代理对象调用的方法中传入的参数
String methodName = method.getName();

//只有当调用的是happy()方法,我们才做happy的代理
if ("happy".equals(methodName)){
System.out.println("open room");
method.invoke(jinlian,args);
System.out.println("clear room");
return null;
}

//只有当调用的方法是collect的时候,才执行收钱的代理
if ("collect".equals(methodName)){
double money = (double) args[0];
System.out.println("扣除中介费 40%: " + money*0.4);
return method.invoke(jinlian, money*0.6);
}

//如果调用的方法是其它的方法的话,则不需要被代理,那么就执行委托者原本的方法
return method.invoke(jinlian,args);
}
});

proxyInstance.happy();
double collect = proxyInstance.collect(800);
System.out.println(collect);

}

一.装饰者

1.Diagrams

decker

2.代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//接口Man
public interface Man {
void eat();
void sleep();
void fight();
}

//类NormalMan 实现 接口Man
public class NormalMan implements Man{
//重写接口中的全部抽象方法
@Override
public void eat() {
System.out.println("stop playing around and eat!");
}

@Override
public void sleep() {
System.out.println("sleep like a log ");
}

@Override
public void fight() {
System.out.println("fight ability : 5 ");
}
}

//类IronMan 实现 接口Man
public class IronMan implements Man {
//这里将被装饰者作为成员变量
private NormalMan normalMan;

public IronMan() {
}

public IronMan(NormalMan normalMan) {
this.normalMan = normalMan;
}

//以下方法不需要被加强 则直接调用方法
@Override
public void eat() {
normalMan.eat();
}

@Override
public void sleep() {
normalMan.sleep();
}

//这里需要加强 则重写以加强方法
@Override
public void fight() {
System.out.println("fight ability : 100 up");
}
}

//Test
@Test
public void deckerTest() {
NormalMan normalMan = new NormalMan();
normalMan.eat();
normalMan.sleep();
normalMan.fight();

IronMan ironMan = new IronMan(normalMan);
ironMan.eat();
ironMan.sleep();
ironMan.fight();
}

//console
stop playing around and eat!
sleep like a log
fight ability : 5

stop playing around and eat!
sleep like a log
fight ability : 100 up

二.适配器

1.Diagrams

decker

2.代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//接口Monk
public interface Monk {
void longSeat();
void patter();
void eatMeat();
void pullWillow();
}

//类MonkAdapter 实现接口Monk 将方法存入适配器
public class MonkAdapter implements Monk{
@Override
public void longSeat() {

}

@Override
public void patter() {

}

@Override
public void eatMeat() {

}

@Override
public void pullWillow() {

}
}

//继承适配器,需要什么就拿什么
public class huaMonk extends MonkAdapter{
public void eatMeat() {
System.out.println("吃肉ing...");
}

public void pullWillow() {
System.out.println("倒拔杨柳ing...");
}
}

public class yixiuMonk extends MonkAdapter{
public void longSeat() {
System.out.println("打坐ing...");
}

public void patter() {
System.out.println("念经ing...");
}
}

@Test
public void adapterTest() {
yixiuMonk yixiu = new yixiuMonk();
yixiu.longSeat();
yixiu.patter();

huaMonk hua = new huaMonk();
hua.eatMeat();
hua.pullWillow();
}

//console

打坐ing...
念经ing...

吃肉ing...
倒拔杨柳ing...

9/20