两种模式的特点
装饰模式:
在不改变接口的前提下,动态扩展对象的访问。
动态继承,让类具有在运行期改变行为的能力。
装饰模式,突出的是运行期增加行为,这和继承是不同的,继承是在编译期增加行为。
强调:增强
代理模式:
在不改变接口的前提下,控制对象的访问。
1.从封装的角度讲,是为了解决类与类之间相互调用而由此导致的耦合关系,可以说是接口的另外一个层引用。
比如:在a类->b代理->c类这个关系中,c类的一切行为都隐藏在b中。即调用者不知道要访问的内容与代理了什么对象。
2.从复用的角度讲,可以解决不同类调用一个复杂类时,仅仅因较小的改变而导致整个复杂类新建一个类。
比如:a类->c类1;b类->c类2。
可以变为a类->ca代理类->c类;b类->cb代理类-c类。
代理模式,是类之间的封装和(某方面的)复用。
强调:限制
举个例子说明问题
下面通过一个例子来说明两者的不同。当我们冲咖啡的时候,首先你要拿咖啡粉冲好一杯咖啡,然后你可以考虑是否加方糖或牛奶。
那么咖啡这个东西就可以通过糖或奶或者糖和奶,变成加糖的咖啡、加奶的咖啡、加糖加奶的咖啡。
但是它还是一杯咖啡,只是它的属性进行了扩展。
接下来分别通过装饰模式与代理模式,模拟这个过程。
1.装饰模式
测试代码:
1 Cafe cafe = new ConcreteCafe(); 2 3 Cafe milkCafe = new MilkDecorator(cafe); 4 milkCafe.getCafe(); 5 System.out.println("----------------------------------------"); 6 Cafe sugarCafe = new SugarDecorator(cafe); 7 sugarCafe.getCafe(); 8 System.out.println("----------------------------------------"); 9 Cafe sugarMilkCafe = new MilkDecorator(new SugarDecorator(new ConcreteCafe())); 10 sugarMilkCafe.getCafe(); 11 System.out.println("----------------------------------------"); 12 Cafe milkSugarCafe = new SugarDecorator(new MilkDecorator(cafe)); 13 milkSugarCafe.getCafe(); 14 System.out.println("----------------------------------------");
就像使用IO流一样:
1 BufferedReader in1 = new BufferedReader(new InputStreamReader(new FileInputStream(file)));//字符流 2 DataInputStream in2 = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));//字节流
// DataInputStream-从数据流读取字节,并将它们装换为正确的基本类型值或字符串
// BufferedInputStream-可以通过减少读写次数来提高输入和输出的速度
对类进行了功能的增强。
2.代理模式
测试代码:
1 Cafe cafe = new Proxy(); 2 cafe.getCafe();
现在可以很清楚的看到:
1. 装饰模式可以让使用者直观的看到增强了哪些功能,而代理模式完全限制了使用者。
2. 对装饰模式来说,装饰者(Decorator)和被装饰者(Cafe)都实现同一个 接口。
3. 对代理模式来说,代理类(Proxy Class)和真实处理的类(Real Class)都实现同一个接口。
4. 此外,不论我们使用哪一个模式,都可以很容易地在真实对象的方法前面或者后面加上自定义的方法。
装饰模式与继承的比较
明显的,装饰模式可以动态的扩展对象的行为。
比如某对象有30项行为,但是在第一阶段用到1-20行为,第二阶段用到11-30项行为,所以这时候,就可以只定义11-20的行为。
在第一阶段运行时,可以将1-10的行为以“装饰1”给加上
到第二阶段运行时,可以将“装饰1”去掉,将21-30的能以“装饰2”给加上。
但是继承是在编译期增加行为。
装饰模式的优缺点
优点:
1. 装饰模式可以提供比继承更多地灵活性。
2. 可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
3. 通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
4. 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。
缺点:
1. 会产生很多的小对象(具体装饰类),增加了系统的复杂性。
2. 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
参考博文:
源码:
装饰者模式:
1 /** 2 * Copyright 2016 Zhengbin's Studio. 3 * All right reserved. 4 * 2016年6月23日 上午11:10:23 5 */ 6 package cafe; 7 8 /** 9 * @author zhengbinMac 10 * 抽象构件角色 11 */ 12 public interface Cafe { 13 14 public void getCafe(); 15 16 }
Cafe.java
1 /** 2 * Copyright 2016 Zhengbin's Studio. 3 * All right reserved. 4 * 2016年6月23日 上午11:11:03 5 */ 6 package cafe; 7 8 /** 9 * @author zhengbinMac 10 * 具体构件角色 11 */ 12 public class ConcreteCafe implements Cafe{ 13 14 @Override 15 public void getCafe() { 16 System.out.println("上一杯原味咖啡!"); 17 } 18 19 }
ConcreteCafe.java
1 /** 2 * Copyright 2016 Zhengbin's Studio. 3 * All right reserved. 4 * 2016年6月23日 上午11:13:41 5 */ 6 package cafe; 7 8 /** 9 * @author zhengbinMac 10 * 装饰角色 11 */ 12 public class Decorator implements Cafe{ 13 14 public Cafe cafe; 15 16 public Decorator(Cafe cafe) { 17 this.cafe = cafe; 18 } 19 20 @Override 21 public void getCafe() { 22 cafe.getCafe(); 23 } 24 25 }
Decorator.java
1 /** 2 * Copyright 2016 Zhengbin's Studio. 3 * All right reserved. 4 * 2016年6月23日 上午11:13:29 5 */ 6 package cafe; 7 8 /** 9 * @author zhengbinMac 10 * 具体装饰角色 11 */ 12 public class MilkDecorator extends Decorator{ 13 14 public MilkDecorator(Cafe cafe) { 15 super(cafe); 16 } 17 18 @Override 19 public void getCafe() { 20 super.getCafe(); 21 this.addMilk(); 22 } 23 24 private void addMilk() { 25 System.out.println("加奶!"); 26 } 27 28 }
MilkDecorator.java
1 /** 2 * Copyright 2016 Zhengbin's Studio. 3 * All right reserved. 4 * 2016年6月23日 上午11:14:22 5 */ 6 package cafe; 7 8 /** 9 * @author zhengbinMac 10 * 具体装饰角色 11 */ 12 public class SugarDecorator extends Decorator{ 13 14 public SugarDecorator(Cafe cafe) { 15 super(cafe); 16 } 17 18 @Override 19 public void getCafe() { 20 super.getCafe(); 21 this.addSugar(); 22 } 23 24 private void addSugar() { 25 System.out.println("加糖!"); 26 } 27 28 }
SugarDecorator.java
1 /** 2 * Copyright 2016 Zhengbin's Studio. 3 * All right reserved. 4 * 2016年6月23日 上午11:18:32 5 */ 6 package cafe; 7 8 import java.io.BufferedInputStream; 9 import java.io.BufferedReader; 10 import java.io.DataInputStream; 11 import java.io.File; 12 import java.io.FileInputStream; 13 import java.io.IOException; 14 import java.io.InputStream; 15 import java.io.InputStreamReader; 16 import java.util.Date; 17 18 /** 19 * @author zhengbinMac 20 * 测试类 21 */ 22 public class Test { 23 24 public static void main(String[] args) throws IOException { 25 Cafe cafe = new ConcreteCafe(); 26 27 Cafe milkCafe = new MilkDecorator(cafe); 28 milkCafe.getCafe(); 29 System.out.println("----------------------------------------"); 30 Cafe sugarCafe = new SugarDecorator(cafe); 31 sugarCafe.getCafe(); 32 System.out.println("----------------------------------------"); 33 Cafe sugarMilkCafe = new MilkDecorator(new SugarDecorator(new ConcreteCafe())); 34 sugarMilkCafe.getCafe(); 35 System.out.println("----------------------------------------"); 36 Cafe milkSugarCafe = new SugarDecorator(new MilkDecorator(cafe)); 37 milkSugarCafe.getCafe(); 38 System.out.println("----------------------------------------"); 39 40 File file = new File("/Users/zhengbinMac/test.txt"); 41 42 FileInputStream in2 = new FileInputStream(file); 43 byte[] tempByte = new byte[1024]; 44 int hasRead = 0; 45 System.out.println("开始时间:" + new Date().getTime()); 46 while((hasRead = in2.read(tempByte)) > 0) { 47 System.out.println(new String(tempByte,0,hasRead)); 48 } 49 System.out.println("结束时间:" + new Date().getTime()); 50 in2.close(); 51 52 System.out.println("----------------------------------------"); 53 54 FileInputStream in4 = new FileInputStream(file); 55 byte[] tempByte2 = new byte[(int)file.length()]; 56 System.out.println("开始时间:" + new Date().getTime()); 57 in4.read(tempByte2); 58 System.out.println("结束时间:" + new Date().getTime()); 59 in4.close(); 60 System.out.println(new String(tempByte2)); 61 62 System.out.println("----------------------------------------"); 63 64 // DataInputStream in3 = new DataInputStream(new FileInputStream(file)); 65 // String s; 66 // System.out.println("开始时间:" + new Date().getTime()); 67 // while((s=in3.readLine()) != null) { 68 // System.out.println(s); 69 // } 70 // System.out.println("结束时间:" + new Date().getTime()); 71 // in3.close(); 72 73 System.out.println("----------------------------------------"); 74 75 // DataInputStream in5 = new DataInputStream(new BufferedInputStream(new FileInputStream(file))); 76 // String s1; 77 // System.out.println("开始时间:" + new Date().getTime()); 78 // while((s1 = in5.readLine()) != null) { 79 // System.out.println(s1); 80 // } 81 // System.out.println("结束时间:" + new Date().getTime()); 82 // in5.close(); 83 84 System.out.println("----------------------------------------"); 85 86 BufferedReader in6 = new BufferedReader(new InputStreamReader(new FileInputStream(file))); 87 String s2; 88 System.out.println("开始时间:" + new Date().getTime()); 89 while((s2 = in6.readLine()) != null) { 90 System.out.println(s2); 91 } 92 System.out.println("结束时间:" + new Date().getTime()); 93 in6.close(); 94 95 System.out.println("----------------------------------------"); 96 97 98 } 99 100 }
Test.java
代理模式:
1 /** 2 * Copyright 2016 Zhengbin's Studio. 3 * All right reserved. 4 * 2016年6月26日 下午8:30:42 5 */ 6 package cafe3; 7 8 /** 9 * @author zhengbinMac 10 * 11 */ 12 public interface Cafe { 13 14 public void getCafe(); 15 16 }
Cafe.java
1 /** 2 * Copyright 2016 Zhengbin's Studio. 3 * All right reserved. 4 * 2016年6月26日 下午8:32:08 5 */ 6 package cafe3; 7 8 /** 9 * @author zhengbinMac 10 * 11 */ 12 public class ConcreteCafe implements Cafe{ 13 14 @Override 15 public void getCafe() { 16 System.out.println("上一杯原味咖啡!"); 17 } 18 19 }
ConcreteCafe.java
1 /** 2 * Copyright 2016 Zhengbin's Studio. 3 * All right reserved. 4 * 2016年6月26日 下午8:33:05 5 */ 6 package cafe3; 7 8 /** 9 * @author zhengbinMac 10 * 11 */ 12 public class Proxy implements Cafe{ 13 14 private ConcreteCafe concreteCafe; 15 16 public Proxy() { 17 this.concreteCafe = new ConcreteCafe(); 18 } 19 20 @Override 21 public void getCafe() { 22 concreteCafe.getCafe(); 23 addMilk(); 24 addSugar(); 25 } 26 27 private void addMilk() { 28 System.out.println("加奶!"); 29 } 30 31 private void addSugar() { 32 System.out.println("加糖!"); 33 } 34 35 }
Proxy.java
1 /** 2 * Copyright 2016 Zhengbin's Studio. 3 * All right reserved. 4 * 2016年6月26日 下午8:38:51 5 */ 6 package cafe3; 7 8 /** 9 * @author zhengbinMac 10 * 11 */ 12 public class Test { 13 14 public static void main(String[] args) { 15 Cafe cafe = new Proxy(); 16 cafe.getCafe(); 17 } 18 19 }
Test.java
继承:
1 /** 2 * Copyright 2016 Zhengbin's Studio. 3 * All right reserved. 4 * 2016年6月23日 上午11:30:41 5 */ 6 package cafe2; 7 8 /** 9 * @author zhengbinMac 10 * 11 */ 12 public class Cafe { 13 14 public void getCafe() { 15 System.out.println("来一杯原味咖啡!"); 16 } 17 18 }
Cafe.java
1 /** 2 * Copyright 2016 Zhengbin's Studio. 3 * All right reserved. 4 * 2016年6月23日 上午11:32:32 5 */ 6 package cafe2; 7 8 /** 9 * @author zhengbinMac 10 * 11 */ 12 public class MilkCafe extends Cafe{ 13 14 @Override 15 public void getCafe() { 16 super.getCafe(); 17 this.addMilk(); 18 } 19 20 private void addMilk() { 21 System.out.println("加奶!"); 22 } 23 }
MilkCafe.java
1 /** 2 * Copyright 2016 Zhengbin's Studio. 3 * All right reserved. 4 * 2016年6月23日 上午11:31:09 5 */ 6 package cafe2; 7 8 /** 9 * @author zhengbinMac 10 * 11 */ 12 public class SugarCafe extends Cafe{ 13 14 @Override 15 public void getCafe() { 16 super.getCafe(); 17 this.addSugar(); 18 } 19 20 private void addSugar() { 21 System.out.println("加糖!"); 22 } 23 }
SugarCafe.java
1 /** 2 * Copyright 2016 Zhengbin's Studio. 3 * All right reserved. 4 * 2016年6月26日 下午3:01:26 5 */ 6 package cafe2; 7 8 /** 9 * @author zhengbinMac 10 * 11 */ 12 public class SugarMilkCafe extends Cafe{ 13 @Override 14 public void getCafe() { 15 super.getCafe(); 16 this.addSugarAndMilk(); 17 } 18 19 private void addSugarAndMilk() { 20 System.out.println("加糖!"); 21 System.out.println("加奶!"); 22 } 23 }
SugarMilkCafe.java
1 /** 2 * Copyright 2016 Zhengbin's Studio. 3 * All right reserved. 4 * 2016年6月23日 上午11:33:22 5 */ 6 package cafe2; 7 8 /** 9 * @author zhengbinMac 10 * 11 */ 12 public class Test { 13 14 public static void main(String[] args) { 15 Cafe milkCafe = new MilkCafe(); 16 milkCafe.getCafe(); 17 18 Cafe sugarCafe = new SugarCafe(); 19 sugarCafe.getCafe(); 20 21 Cafe sugarMilkCafe = new SugarMilkCafe(); 22 sugarMilkCafe.getCafe(); 23 } 24 25 }
Test.java