设计模式——代理模式与装饰模式的异同

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式——代理模式与装饰模式的异同相关的知识,希望对你有一定的参考价值。

两种模式的特点


装饰模式:

  在不改变接口的前提下,动态扩展对象的访问。
  动态继承,让类具有在运行期改变行为的能力。
  装饰模式,突出的是运行期增加行为,这和继承是不同的,继承是在编译期增加行为
  强调:增强

代理模式:

  在不改变接口的前提下,控制对象的访问。
  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. 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

 

参考博文:

UML类图

修饰模式与代理模式的区别

设计模式之——装饰模式与代理模式的区别

Java之美——设计模式

装饰者模式

源码:

装饰者模式:

 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     
java动态代理

IO流的设计模式

代理模式、装饰者模式

装饰模式与代理模式的区别

java代理模式与装饰者模式

对设计模式的总结之装饰模式与代理模式