设计模式之装饰器
- 装饰者模式:
动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
- 适用性:
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
- 处理那些可以撤消的职责。
- 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
- 我的理解是:
装饰者模式就好比一个个wrapper(包装器),将一个对象一层层的包装,然后返回包装后的对象,就好比你在网上购买了一个电饭锅,那么这个电饭锅就是最原始的对象,而商家可能会在发货时进行一个初步包装,首先将电饭锅用一层泡沫包起来,然后装入一个纸箱,接着交给快递公司,然后快递公司收到这个物品后,还要进行二次包装,即使用快递公司专门的盒子装起来(或者用麻袋装好),然后贴上胶布开始运输,客户收到的这个箱子自后,一层层解开包装,最后拿出电饭锅。那么所有包装这个电饭锅的东西,像泡沫啊,纸箱啊,盒子啊,胶布啊,都可以算作装饰者,装饰者将原来的对象装饰完之后,会生成一个装饰后的对象,使源对象加上各种装饰品。所以,既然装饰者依赖于被装饰的对象,那么,装饰者在实现时就理所当然需要一个被装饰的对象的引用了,然后装饰完之后该引用就会指向装饰后的对象了。
所以,装饰者模式一定要搞明白装饰者的使用方式。 - 另外,因为装饰者能够替换源对象,所以在实际实现时需要将装饰者和源对象继承同一个父类(这个和实际有所不同,实际中,装饰者和源对象是不同的对象种类,但设计总归设计,不能总是和实际完美的相符,是需要一些灵活的处理的,而且这种设计的其本质是装饰者装饰之后的对象和源对象属于同一个父类,就好比电饭锅和装在盒子里的电饭锅都是电饭锅一样,但盒子并不是电饭锅)
- 还有一点就是,实际实现的装饰者,是装饰源对象的某个方法,相当于将被装饰的对象的某个方法增添或替换成某种方法而不改变源对象的代码和结构,就相当于动态的改变某种功能。
代码:
1 public interface IProduct { 2 public void transport(); 3 } 4 5 public class Product implements IProduct{ 6 7 private String name; 8 9 10 public Product(String name) 11 { 12 this.name=name; 13 } 14 15 public void transport() 16 { 17 System.out.println("原始的产品:"+this.name); 18 System.out.println("运输..."); 19 } 20 21 @Override 22 public String toString() { 23 return "Product [name=" + name + "]"; 24 } 25 26 27 } 28 29 30 public class Decorator1 extends Decorator{ 31 private IProduct product; 32 private String name; 33 34 35 public Decorator1(IProduct product) 36 { 37 this.product=product; 38 this.name="泡沫"; 39 } 40 public void transport() 41 { 42 System.out.println("用"+this.name+"包装"); 43 if(this.product != null) 44 { 45 this.product.transport(); 46 } 47 } 48 @Override 49 public String toString() { 50 return "Decorator1 [product=" + product + ", name=" + name + "]"; 51 } 52 53 } 54 55 56 public class Decorator2 extends Decorator{ 57 private IProduct product; 58 private String name; 59 60 61 public Decorator2(IProduct product) 62 { 63 this.product=product; 64 this.name="纸盒"; 65 } 66 public void transport() 67 { 68 System.out.println("用"+this.name+"包装"); 69 if(product != null) 70 { 71 this.product.transport(); 72 } 73 } 74 75 } 76 77 78 public class Test { 79 80 /** 81 * @param args 82 */ 83 public static void main(String[] args) { 84 IProduct product=new Product("电饭锅"); 85 86 product=new Decorator1(product);//用泡沫包装 87 //String name=product.toString(); 88 //System.out.println(name); 89 90 product=new Decorator2(product);//用纸盒包装 91 /*之后product对象就是被纸盒包装又被泡沫包装的对象了*/ 92 product.transport();//从外到里依次输出包装物直到原产品,最后进行运输 93 94 } 95 96 }
用纸盒包装
用泡沫包装
原始的产品:电饭锅
运输...
结论:先调用外围包装的对象方法,之后由外向内调用内部层的对象。