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