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对象的处理。

    金麟岂是池中物,一遇风云便化龙!
  • 相关阅读:
    Gradview读取Excel表并插入数据库
    键盘上每个键作用!!! (史上最全的)­
    经典SQL语句大全
    [转帖] 一个老乞丐的一句话,震惊全中国人!
    GridView控件实现自定义数字、时间、货币字符串格式
    .net连接数据库相关
    论坛Email验正的正则表达式升级
    自定义DBHelper类
    在线编辑器CuteEditor使用方法
    asp.net中验证码的生成
  • 原文地址:https://www.cnblogs.com/ABKing/p/12333905.html
Copyright © 2011-2022 走看看