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

  • 相关阅读:
    HDU1720 A+B Coming
    HDU1390 ZOJ1383 Binary Numbers
    HDU1390 ZOJ1383 Binary Numbers
    HDU2504 又见GCD
    HDU2504 又见GCD
    HDU1335 POJ1546 UVA389 UVALive5306 ZOJ1334 Basically Speaking
    HDU1335 POJ1546 UVA389 UVALive5306 ZOJ1334 Basically Speaking
    HDU1020 ZOJ2478 Encoding
    HDU1020 ZOJ2478 Encoding
    HDU2097 Sky数
  • 原文地址:https://www.cnblogs.com/liuzhen1995/p/5978767.html
Copyright © 2011-2022 走看看