• 结构型模式:装饰模式


    文章首发:
    结构型模式:装饰模式

    花

    七大结构型模式之四:装饰模式。

    简介

    姓名 :装饰模式

    英文名 :Decorator Pattern

    价值观 :人靠衣装,类靠装饰

    个人介绍
    Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality.
    动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。
    (来自《设计模式之禅》)

    你要的故事

    夏天到了,吃货们期待的各种各样冷冻零食就要大面积面向市场,什么冰淇淋、雪糕、冰棍等等。今天的装饰模式不讲这些都受欢迎的零食,讲讲那乌黑滴龟苓膏。不知道大伙们喜不喜欢吃龟苓膏,我是挺喜欢的,不喜欢的人很多都闲它苦,应该没有人愿意在没加任何糖类的情况下吃龟苓膏。很多糖水店会提供几种龟苓膏,比如蜂蜜龟苓膏、牛奶龟苓膏。下面我们空想出一个场景来。

    天气到了 30℃,小明和小红加班到了 10 点,一起下班,路过一家糖水店,小红萌生了吃糖水解解热的想法,小明最近涨薪,就提出要请小红吃糖水,他们进去糖水店,小红想着好久没吃龟苓膏了,就想吃吃,怀念一下童年那段在农村夜晚吃龟苓膏的时光。糖水店里面有 3 种龟苓膏,一种是普通龟苓膏(这老板居然提供不加任何糖分的,过分了),一种是蜂蜜龟苓膏,另外一种是牛奶龟苓膏,小明点了一份蜂蜜龟苓膏,小红想加蜂蜜和牛奶,就咨询了老板娘,能否同时加蜂蜜和牛奶,老板娘用那东北腔爽快地回复小红:行。小明和小红就等龟苓膏上桌。。。脑洞到这。

    我们来把这个故事套入到装饰模式里去。上面故事里老板卖 3 种龟苓膏,而都不满足小红的需求,小红想要的是蜂蜜牛奶龟苓膏,如果用继承来实现龟苓膏,那就无法满足小红的要求了,因为继承直接固定了龟苓膏的做法,加什么就是什么,要蜂蜜牛奶龟苓膏,那就需要另外一个龟苓膏类代表蜂蜜牛奶龟苓膏;而用装饰模式则不同,下面看看装饰模式的实现代码。

    龟苓膏抽象类,该类定义了制作龟苓膏的抽象方法。

    /**
     * 龟苓膏
     */
    abstract class HerbalJelly {
    
        /**
         * 制作龟苓膏方法
         */
        public abstract void process();
    
    }
    

    老板提供的最基本的龟苓膏,这种龟苓膏不加任何料,就是那苦苦的龟苓膏,我们称它为普通龟苓膏。

    /**
     * 普通龟苓膏
     */
    class CommonHerbalJelly extends HerbalJelly {
    
        @Override
        public void process() {
            System.out.println("盛一碗龟苓膏");
        }
        
    }
    

    另外 2 种龟苓膏:蜂蜜龟苓膏和牛奶龟苓膏,不是用继承实现,而是用装饰器实现,我们可以发现这 2 种龟苓膏都是基于上面普通龟苓膏添加不同的糖类食品制作而成。下面实现一个抽象类充当装饰器。

    /**
     * 龟苓膏装饰器
     */
    abstract class Decorator extends HerbalJelly {
    
        private HerbalJelly herbalJelly;
    
        public Decorator(HerbalJelly herbalJelly) {
            this.herbalJelly = herbalJelly;
        }
    
        @Override
        public void process() {
            this.herbalJelly.process();
        }
    }
    

    接下来就根据上面的龟苓膏装饰器来实现蜂蜜龟苓膏和牛奶龟苓膏。

    /**
     * 蜂蜜龟苓膏
     */
    class HoneyHerbalJelly extends Decorator{
    
        public HoneyHerbalJelly(HerbalJelly herbalJelly) {
            super(herbalJelly);
        }
    
        @Override
        public void process() {
            super.process();
            System.out.println("加蜂蜜");
        }
    }
    
    /**
     * 牛奶龟苓膏
     */
    class MilkHerbalJelly extends Decorator{
    
        public MilkHerbalJelly(HerbalJelly herbalJelly) {
            super(herbalJelly);
        }
    
        @Override
        public void process() {
            super.process();
            System.out.println("加牛奶");
        }
    }
    

    下面提供我们的测试代码,还记得上面说的,小明要了一碗蜂蜜龟苓膏,小红则要了一碗蜂蜜牛奶龟苓膏。

    public class DecoratorTest {
    
        public static void main(String[] args) {
            CommonHerbalJelly commonHerbalJelly = new CommonHerbalJelly();
            HoneyHerbalJelly honeyHerbalJelly = new HoneyHerbalJelly(commonHerbalJelly);
            // 小明的蜂蜜龟苓膏
            honeyHerbalJelly.process();
    
            MilkHerbalJelly milkHerbalJelly = new MilkHerbalJelly(honeyHerbalJelly);
            // 小红的蜂蜜牛奶龟苓膏
            milkHerbalJelly.process();
        }
    
    }
    
    打印结果:
    盛一碗龟苓膏
    加蜂蜜
    盛一碗龟苓膏
    加蜂蜜
    加牛奶
    

    我们看到,小明的龟苓膏只加蜂蜜,小红的龟苓膏加了蜂蜜和牛奶,这样就很简单的满足了小红的要求。

    总结

    装饰模式在一些类与类之间有叠加效应(也就是给一个类增加附加功能)的场景中非常好用,它可以说是继承的替代品,有更好的扩展性,也比较灵活。在 Java JDK 源码中也大面积用到了装饰模式,比如:java.io.BufferedInputStream(InputStream)。学完基础知识后,可以看看源码中是怎么实现的,巩固知识。

    推荐阅读

    结构型模式:组合模式

    结构型模式:桥接模式

    结构型模式:适配器模式

    公众号后台回复『大礼包』获取 Java、Python、IOS 等教程
    加个人微信备注『教程』获取架构师、机器学习等教程

    LieBrother

  • 相关阅读:
    Java学习过程中的总结的小知识点(长期更新)
    年月日与time的相互转换
    Androidstudio预览时出现错误java.lang.NoClassDefFoundError: com/android/util/PropertiesMap
    eclipse中配置struts2出现There is no Action mapped for namespace [/] and action name [Login] associated wi
    struts2出错java.lang.NoClassDefFoundError: org/apache/commons/lang3/StringUtils
    第一次部署Struts2时出现错误java.lang.ClassNotFoundException: org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.class
    由JDK1.8降为JDK1.6时配置环境变量不起作用
    Androidstudio报错UnsupportedClassVersionError
    AndroidStudio导入Library
    Ubuntu下su被拒绝
  • 原文地址:https://www.cnblogs.com/liebrother/p/10788317.html
Copyright © 2020-2023  润新知