zoukankan      html  css  js  c++  java
  • 设计模式学习笔记(三:装饰模式)

    1.1概述

        在许多设计中,可能需要改进类的某个对象的功能,而不是该类创建的全部对象,在这样的情况下,就可以使用装饰模式。

        例如,麻雀类的实例(麻雀)能够连续飞行100米,如果用麻雀类创建了5只麻雀,那么这5只麻雀都能连续飞行100米。假如想让其中一只麻雀能够连续飞行150米,那应当怎样做呢?一种比较好的办法就是给麻雀装上智能电子翅膀,智能电子翅膀可以使得麻雀不使用自己的翅膀就能飞行50米。

        装饰模式是动态地扩展一个对象的功能,而不需要改变原始类代码的一种成熟模式。在装饰模式中,“具体组件”类和“具体装饰”类是该模式中最重要的两个角色。“具体组件”类的实例称作“被装饰者”,“具体装饰”类的实例称为“装饰者”。“具体装饰”类需要包含有“具体组件”类的一个实例的引用,以便装饰“被装饰者”。例如,前面所述的麻雀类就是“具体组件”类,而一只麻雀就是“具体组件”类的一个实例,即是一个“被装饰者”,而安装了电子翅膀的麻雀就是“具体装饰”类的一个实例,即安装了电子翅膀的麻雀就是麻雀的“装饰者”。

    1.2模式的结构

        装饰模式的结构中包括以下四种角色:

    (1)抽象组件(Component):抽象组件是一个抽象类。抽象组件定义了“被装饰者”需要进行“装饰“的方法。

    (2)具体组件(ConcreteComponent):具体组件是抽象组件的一个子类,具体组件的实例称为“被装饰者“。

    (3)装饰(Decorator):装饰也是抽象组件的一个子类,但装饰还包含一个抽象组件声明的变量以保存“被装饰者“的引用。装饰可以是一个抽象类也可以是一个非抽象类,如果是非抽象类,该类的实例称为”装饰者“。

    (4)具体装饰(ConcreteDecorator):具体装饰是装饰的一个非抽象子类,具体装饰的实例称为“装饰者“。

        装饰模式结构的类图如下所示:

     

    1.3装饰模式的优点

    (1)被装饰者和装饰者是松耦合关系。由于装饰仅仅依赖于抽象组件,因此具体装饰只知道它要装饰的对象是抽象组件某一个子类的实例,但不需要知道是哪一个具体子类。

    (2)装饰模式满足“开-闭原则“。不必修改具体组件,就可以增加新的针对该具体组件的具体装饰。

    (3)可以使用多个具体装饰来装饰具体组件组件的实例。

    1.4适合使用装饰模式的情景

    (1)程序希望动态地增强类的某个对象的功能,而又不影响到该类的其他对象。

    (2)采用继承来增强对象功能不利于系统的扩展和维护。

    1.5装饰模式的使用

      下面通过一个简单的实例,实现1.1概述中简单例子:假设系统中有一个Bird抽象类以及Bird类的一个子类SparrowSparrow类实现了Birdfly方法,使得Sparrow类创建的对象(麻雀)调用fly()方法能连续飞行100米。

      现在,用户需要两只鸟,无论是那种鸟都可以,但必须分别能连续飞行150米和200米。显然,现有的系统无法向用户提供这样的Bird对象,所以需要修改现有的系统。此处,使用装饰者模式,即可实现不必修改系统的代码,只需在系统中添加“装饰”,该系统将可以创建出用户需要的鸟。具体如下:

     首先看一下本实例构建框架具体类和1.2模式的结构中类图的对应关系,如下图3所示:

     

    图3  具体编写类及接口与类图对应关系

    (1)抽象组件

    本问题中,抽象组件Bird规定了具体组件需要实现方法,Bird类的代码如下:

    package com.liuzhen.three_decorator;
    
    public abstract class Bird {
        public abstract int fly();
    }

    (2)具体组件

    对于本问题,具体组件是Sparrow类,该类在实现fly()方法时,将该方法的返回值设置为100Sparrow类的代码如下:

    package com.liuzhen.three_decorator;
    
    public class Sparrow extends Bird{
        public final int DISTANCE = 100;
        public int fly(){
            return DISTANCE;
        }
    }

    (3)装饰

    本问题中,装饰类是一个抽象类,该类包含有一个Bird声明的变量以保存“被装饰者”的引用。代码如下:

    package com.liuzhen.three_decorator;
    
    public abstract class Decorator extends Bird {
        protected Bird bird;
        public Decorator(){
            
        }
        public Decorator(Bird bird){
            this.bird = bird;
        }
    }

    (4)具体装饰

    根据具体的问题,具体装饰经常委托“被装饰者”调用相应的方法。本问题中具体装饰类是SparrowDecorator类,该类的代码如下:

    package com.liuzhen.three_decorator;
    
    public class SparrowDecorator extends Decorator{
        public final int DISTANCE = 50;  //eleFly方法能飞50米
        SparrowDecorator(Bird bird){
            super(bird);                 //表示调用父类(Decorator)的构造函数
        }
        public int fly(){
            int distance = 0;
            distance = bird.fly() + eleFly();   //委托被装饰者bird调用fly(),然后再调用eleFly()
            return distance;
        }
        /*
         * eleFly()方法访问权限设置为private,其目的是使得客户程序只有调用fly方法才可以使用eleFly方法
         */
        private int eleFly(){             //装饰者新添加的方法
            return DISTANCE;
        }
    }

    (5)具体使用

        通过ThreeApllication类来具体实现上述相关类和接口,来实现适配器模式的运用,其代码如下:

    package com.liuzhen.three_decorator;
    
    public class ThreeApplication {
        public void needBird(Bird bird){
            int flyDistance = bird.fly();
            System.out.println("这只鸟能飞行"+flyDistance+"米");
        }
        public static void main(String[] args) {
            ThreeApplication client = new ThreeApplication();
            Bird sparrow = new Sparrow();          //sparrow只能飞行100米
            Bird sparrowDecorator1 = new SparrowDecorator(sparrow);   //sparrowDecorator1能飞行150米
            Bird sparrowDecorator2 = new SparrowDecorator(sparrowDecorator1); //sparrowDecorator2能飞行200米
            client.needBird(sparrowDecorator1);
            client.needBird(sparrowDecorator2);
        }
    }

    运行结果如下:

    这只鸟能飞行150米
    这只鸟能飞行200米

    参考资料:

          1.Java设计模式/耿祥义,张跃平著.——北京:清华大学出版社,2009.5

  • 相关阅读:
    c#与JavaScript实现对用户名、密码进行RSA非对称加密
    NPOI操作EXCEL(五)——含合并单元格复杂表头的EXCEL解析
    NPOI操作EXCEL(四)——反射机制批量导出excel文件
    NPOI操作EXCEL(三)——反射机制进行excel表格数据的解析
    NPOI操作EXCEL(二)——大量不同模板时设计方式
    由一个投票算法引发的思考
    .NET WebAPI 实现图片上传(包括附带参数上传图片)
    .NET WebAPI 用ExceptionFilterAttribute实现错误(异常)日志的记录(log4net做写库操作)
    .NET WebAPI 用ActionFilterAttribute实现token令牌验证与对Action的权限控制
    js中的console
  • 原文地址:https://www.cnblogs.com/liuzhen1995/p/5978767.html
Copyright © 2011-2022 走看看