装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
假设一个场景:我们要生产一辆车,所以需要一个Car类,但是我们需要增加新的功能,比如飞,游泳等,所以我们需要写出Car类的子类,比如FlyCar、SwimCar等。但是,如果我们需要一辆既会飞,又会游泳的车,我们就需要再新增一个类。当我们这样的需求很多的时候,这样带来的问题是:子类过多。因此,我们引入了装饰器模式。
把被装饰对象和装饰对象共有的特性抽象成一个接口:
1 package top.bigking.decorator; 2 3 /** 4 * @Author ABKing 5 * @since 2020/2/19 下午11:12 6 **/ 7 public interface ICar { 8 /** 9 * 车子的功能 10 */ 11 void fun(); 12 }
写一个被装饰对象,实现了ICar接口:
1 package top.bigking.decorator; 2 3 /** 4 * @Author ABKing 5 * @since 2020/2/19 下午11:18 6 **/ 7 public class Car implements ICar { 8 @Override 9 public void fun() { 10 System.out.println("地上跑"); 11 } 12 }
写一个装饰器:
装饰器的核心在于,它持有被装饰的对象:
1 package top.bigking.decorator; 2 3 /** 4 * @Author ABKing 5 * @since 2020/2/19 下午11:19 6 **/ 7 public class DecoratorCar implements ICar { 8 private ICar car; 9 10 public DecoratorCar(ICar car) { 11 this.car = car; 12 } 13 14 @Override 15 public void fun() { 16 car.fun(); 17 } 18 }
fun()方法中的car.fun()很重要,因为装饰器类是需要被集成的,所以装饰器的fun()方法会被调用,也就是说,装饰器必须在被装饰对象已有的功能上进行装饰。
当我们需要一辆会飞的车时,只需要写一个FlyCar集成Decorator类即可:
1 package top.bigking.decorator; 2 3 /** 4 * @Author ABKing 5 * @since 2020/2/19 下午11:20 6 **/ 7 public class FlyCar extends DecoratorCar { 8 public FlyCar(ICar car) { 9 super(car); 10 } 11 12 @Override 13 public void fun() { 14 super.fun(); 15 System.out.println("有飞的功能!"); 16 } 17 }
可以很明显的看到,以上代码的fun()方法中,调用了父类的fun()方法,也就是装饰器的fun()方法,而我们又知道,装饰器的fun()方法调用的是被装饰对象的fun()方法,也就是说,我们完成了在传入的ICar对象的基础上,扩展了新的功能。
接下来我们按这个方法再写一个SwimCar类:
1 package top.bigking.decorator; 2 3 /** 4 * @Author ABKing 5 * @since 2020/2/19 下午11:21 6 **/ 7 public class SwimCar extends DecoratorCar { 8 public SwimCar(ICar car) { 9 super(car); 10 } 11 12 @Override 13 public void fun() { 14 super.fun(); 15 System.out.println("有游泳的功能!"); 16 } 17 }
那么问题来了,在我们一开始假设的场景中,要获得一辆既会飞,又会游泳的车,需要再写一个子类,现在使用了装饰器模式,我们不需要写了,只需要new一辆基础的被装饰对象,也就是ICar car = new Car();即可,然后在此基础上,把car传入FlyCar的构造器中,ICar flyCar = new FlyCar(car);我们就能获得一辆会飞的车,flyCar,此时,把flyCar传入SwimCar的构造器中,我们就获得了一辆既会飞,又会游泳的车了。
JUnit单元测试如下:
1 package top.bigking.decorator; 2 3 import org.junit.Test; 4 5 /** 6 * @Author ABKing 7 * @since 2020/2/19 下午11:23 8 **/ 9 public class TestDecorator { 10 @Test 11 public void testDecorator(){ 12 ICar car = new Car(); 13 ICar flyCar = new FlyCar(car); 14 ICar swimCar = new SwimCar(car); 15 ICar flyAndSwimCar = new SwimCar(flyCar); 16 flyAndSwimCar.fun(); 17 } 18 }
运行结果如下:
地上跑
有飞的功能!
有游泳的功能!
开发中使用的场景:
IO中输入流和输出流的设计
Swing包中图形界面构件功能
Servlet API中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper,HttpServletRequestWrapper类,增强了request对象的功能。
Struts2中,request,response,session对象的处理。
原文:https://www.cnblogs.com/ABKing/p/12333905.html