zoukankan      html  css  js  c++  java
  • 装饰器模式

    装饰器模式(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对象的处理。

    金麟岂是池中物,一遇风云便化龙!
  • 相关阅读:
    deflate树与deflate编码
    生产者消费者模式下的并发无锁环形缓冲区
    环形缓冲区的设计及其在生产者消费者模式下的使用(并发有锁环形队列)
    zeromq源码分析笔记之无锁队列ypipe_t(3)
    zeromq源码分析笔记之线程间收发命令(2)
    zeromq源码分析笔记之架构(1)
    PHP和golang差异见解
    关于助力红包随机分配思考总结
    TCP四次挥手
    TCP三次握手
  • 原文地址:https://www.cnblogs.com/ABKing/p/12333905.html
Copyright © 2011-2022 走看看