装饰器模式

装饰器模式(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