浅谈设计模式-代理模式和装饰模式

代理模式和装饰模式十分相似,连类图都长得差不多,不过二者用来解决的问题不同,代理模式为其它对象提供一种代理,目的是为了隐藏其具体的实现细节和控制这个对象的访问(就比如通过代理上网)。而装饰模式是通过迭代来为一个对象增加额外的行为,而这个对象本身不变(比如人穿了多件衣服,但人本身不变)。在这里要加以区分。

代理模式

UML类图

代理模式
代理模式中,代理类和真实类均继承于相同的抽象父类或是实现相同的接口,代理类持有真实类的引用,用户直接接触的对象是代理类,代理类在控制用户的访问的同时隐藏了真实类的实现细节。

代码实现

1
2
3
4
public interface INetClient {
void connectToServer(String serverAddress);
void sendMessage(String msg);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 真正与server通信的类
* @author Administrator
*/
public class Client implements INetClient{
private String clientAddress="192.168.0.1";
private Server server;
@Override
public void connectToServer(String serverAddress) {
// TODO Auto-generated method stub
server=new Server(serverAddress);
server.connect(clientAddress);//连接
}
@Override
public void sendMessage(String msg) {
// TODO Auto-generated method stub
server.send(msg);//发消息
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 代理类
* @author Administrator
*/
public class ClientProxy implements INetClient{
private String clientAddress="192.168.0.2";
private INetClient client=new Client();
@Override
public void connectToServer(String serverAddress) {
// TODO Auto-generated method stub
client.connectToServer(serverAddress);
}
@Override
public void sendMessage(String msg) {
// TODO Auto-generated method stub
client.sendMessage(msg);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Server {
private String serverAddress;
private String clientAddress;
public Server(String serverAddress) {
this.serverAddress = serverAddress;
}
public void connect(String clientAddress){
if(clientAddress.endsWith("1")){//判断地址是否合法
this.clientAddress=clientAddress;
System.out.println(clientAddress+" 已连接至服务器 "+serverAddress);
}
}
public void send(String msg){
if(clientAddress!=null){
System.out.println(clientAddress+" 向服务器发送了 "+msg);
}
}
}
1
2
3
4
5
6
7
public class TestProxy {
public static void main(String[]args){
INetClient client=new ClientProxy();
client.connectToServer("192.168.0.100");
client.sendMessage("hello world");
}
}

运行结果:

1
2
192.168.0.1 已连接至服务器 192.168.0.100
192.168.0.1 向服务器发送了 hello world

在Android中的应用

在 Android 中也有不少代理类的实现,我们经常打交道的就是 ActivityManagerProxy 了,其代理的是 ActivityManagerNative ,两者均实现了 IActivityManger 接口,而 ActivityManagerNative 作为一个抽象类,其具体实现是 ActivityManagerService ,两者运行于不同的进程,通过Binder机制进行通信。我们平时启动 Activity、Service 等操作都是通过本地 ActivityManagerProxy 来与 ActivityManagerService 进行交流的。 ActivityManagerService 的实现细节我们并不需要关心,只需要与其代理类进行交流即可。

装饰模式

UML类图

装饰模式
装饰模式和代理模式实现方式类似,我们可以对一个对象进行多层装饰,每层装饰均可实现特定的装饰功能。最终我们接触的是经过装饰之后的类,中间的装饰层对我们来说是透明的。

代码实现

1
2
3
4
5
6
7
8
9
/**
* 定义饮料接口
* @author Administrator
*
*/
public interface Drink {
public String getDescription();
public float getPrice();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 原始类
* @author Administrator
*
*/
public class Coffee implements Drink {
private String description="冲了一包咖啡";
private float price=10;
@Override
public String getDescription() {
// TODO Auto-generated method stub
return description;
}
@Override
public float getPrice() {
// TODO Auto-generated method stub
return price;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 原始类
* @author Administrator
*
*/
public class Tea implements Drink {
private String description="泡了一杯茶";
private float price=12;
@Override
public String getDescription() {
// TODO Auto-generated method stub
return description;
}
@Override
public float getPrice() {
// TODO Auto-generated method stub
return price;
}
}
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
/**
* 装饰类
* @author Administrator
*
*/
public class SugerDecorator implements Drink {
private Drink drink;
private String description="加入一勺糖";
private float price=1.5f;
public SugerDecorator(Drink drink) {
this.drink = drink;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return drink.getDescription()+description;
}
@Override
public float getPrice() {
// TODO Auto-generated method stub
return drink.getPrice()+price;
}
}
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
/**
* 装饰类
* @author Administrator
*
*/
public class SaltDecorator implements Drink {
private Drink drink;
private String description="加入一勺盐";
private float price=1;
public SaltDecorator(Drink drink) {
this.drink = drink;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return drink.getDescription()+description;
}
@Override
public float getPrice() {
// TODO Auto-generated method stub
return drink.getPrice()+price;
}
}
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
/**
* 装饰类
* @author Administrator
*
*/
public class PepperDecorator implements Drink {
private Drink drink;
private String description="加入一勺辣椒粉";
private float price=2;
public PepperDecorator(Drink drink) {
this.drink = drink;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return drink.getDescription()+description;
}
@Override
public float getPrice() {
// TODO Auto-generated method stub
return drink.getPrice()+price;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class TestDecorator {
public static void main(String[]args){
Drink coffee=new Coffee();
Drink tea=new Tea();
Drink sugerCoffee=new SugerDecorator(coffee);
Drink saltCoffee=new SaltDecorator(coffee);
Drink pepperCoffee=new PepperDecorator(coffee);
Drink sugerTea=new SugerDecorator(tea);
Drink saltTea=new SaltDecorator(tea);
Drink pepperTea=new PepperDecorator(tea);
System.out.println(coffee.getDescription()+";价格="+coffee.getPrice());
System.out.println(tea.getDescription()+";价格="+tea.getPrice());
System.out.println(sugerCoffee.getDescription()+";价格="+sugerCoffee.getPrice());
System.out.println(saltCoffee.getDescription()+";价格="+saltCoffee.getPrice());
System.out.println(pepperCoffee.getDescription()+";价格="+pepperCoffee.getPrice());
System.out.println(sugerTea.getDescription()+";价格="+sugerTea.getPrice());
System.out.println(saltTea.getDescription()+";价格="+saltTea.getPrice());
System.out.println(pepperTea.getDescription()+";价格="+pepperTea.getPrice());
}
}

运行结果:

1
2
3
4
5
6
7
8
冲了一包咖啡;价格=10.0
泡了一杯茶;价格=12.0
冲了一包咖啡加入一勺糖;价格=11.5
冲了一包咖啡加入一勺盐;价格=11.0
冲了一包咖啡加入一勺辣椒粉;价格=12.0
泡了一杯茶加入一勺糖;价格=13.5
泡了一杯茶加入一勺盐;价格=13.0
泡了一杯茶加入一勺辣椒粉;价格=14.0

在Android中的应用

Android 中的 Context 体系就是装饰模式很好的应用,Activity 继承于 ContextThemeWrapper,而 ContextThemeWrapper、Service 和 Application,均继承于 ContextThemeWrapper,ContextWrapper 持有 ContextImpl的引用,ContextImpl 则实现了 Context 中定义的方法。在这里,ContextWrapper以及其子类,均装饰了ContextImpl类。我们在Activity、Service或是Application中均可以直接调用到Context中定义的方法,而不用关心中间的装饰过程,因为其装饰过程不同,所以其最终表现的结果也可能是不同的,但这些对我们来说都是透明的。

总结

代理模式和装饰模式因为结构比较类似,所以这里将两者一起进行论述,以加深印象。目前在工作中代理模式用的多一点,大多用在 Android 网络请求中,配合弱引用,对网络请求的callback进行封装,可以有效避免内存泄漏。

文章目录
  1. 1. 代理模式
    1. 1.1. UML类图
    2. 1.2. 代码实现
    3. 1.3. 在Android中的应用
  2. 2. 装饰模式
    1. 2.1. UML类图
    2. 2.2. 代码实现
    3. 2.3. 在Android中的应用
  3. 3. 总结
|