设计模式系列之「装饰模式」

小Y:Hello,大家好,欢迎来到魂斗罗.归来的世界,下面让小Y带领大家一起去采访一下叼烟大汉比尔·雷泽,让大家更加理解这个粗狂的战斗汉子。Let's go。!

小Y:你最喜欢干什么?

比尔·雷泽:最喜欢冲关打爆大机。

小Y:比尔,你想对观众说些什么?

比尔·雷泽:想挑战我,随时奉陪!一颗不够,给你来三颗!

小Y:......

比尔·雷泽作为魂斗罗这么经典的人物,原来也是一个粗狂耿直boy呀。为了保存住他的光辉形象和让大家更加了解他,小Y决定把比尔·雷泽的攻击技能装饰一番介绍给大家认识。

一、案例设想

比尔·雷泽在战场上在战场上基本上用散弹枪可以横扫小兵,但是遇到一些特殊的情况还是需要通过G5手雷、集速手雷、爆破飞弹等技能来进行辅助。那么如何设置这些技能才合适呢?简单,小Y脑海中立马闪过几种方案:

(1)采用继承的方式,设定一个比尔·雷泽类,有多少个技能就写多少个子类来继承这个比尔·雷泽类。

看完这个图,小Y自己都蒙逼了,每增加一个技能可以组合出N个子类,这只是一个比尔·雷泽,再来个艾薇、寒锋什么的,那不就要加到天荒地老?

(2)直接抽象一个角色类,里面包含了每个角色的技能。

这样子有多少个角色就增加多少个子类就可以了,不用根据技能增加类,避免造成子类爆炸,但是,每个角色的技能是可以叠加使用的,角色越多或者技能叠加种类越多,那么就要在超类增加越多的方法,而且直接修改超类不符合开闭原则(超类对扩展开放,对修改关闭)。

(3)今天的主题— 装饰模式。

二、装饰模式的概念

1.装饰模式定义

装饰模式(Decorator Pattern)是一种比较常见的模式,动态地给一个对象添加一些额外的职责(就增加功能来说,装饰模式相比生成子类更为灵活)。

2.使用的场景

  • 需要扩展一个类的功能,或者给一个类添加附加职责(即核心功能不变,对其进行扩展)。
  • 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实,使得子类数目呈爆炸性增长。

3.角色介绍

  • Component抽象构件

    Component是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象(在装饰模式中,必然有一个最基本、最核心、最原始的接口或抽象类充当Component抽象构件) 。

  • ConcreteState具体状态角色

    ConcreteComponent 具体构件,是Component的具体实现,要装饰的就是它 。

  • Decorator装饰角色

    一般是一个抽象类,实现Component接口或者抽象方法,它里面可不一定有抽象的方法呀,在它的属性里必然有一个private变量指向Component抽象构件(如果具体装饰角色只有一个,这个可以省略)。

  • ConcreteDecorator具体装饰角色

    把你最核心的、最原始的、最基本的东西装饰成想要的东西。

4.案例实现

(1)装饰模式实现角色装饰UML图

①抽象角色类

public abstract class Character {
    public abstract void attack();
} 

②实现角色比尔·雷泽(对它进行装饰)

public class BillRizer extends Character {
    @Override
    public void attack() {
        //角色最基本的技能
        System.out.print("散弹枪进行扫射!");
    }
}

③技能装饰抽象类

public abstract class SkillDecorator extends Character{
    private Character character;

    public SkillDecorator(Character character) {
        this.character = character;
    }

    @Override
    public void attack() {
        this.character.attack();
    }
}

④G5手雷技能

public class G5GrenadeDecorator extends SkillDecorator {
    public G5GrenadeDecorator(Character character) {
        super(character);
    }

    @Override
    public void attack() {
        super.attack();
        System.out.print("G5手雷辅助攻击!");
    }
}

⑤集速手雷技能

public class SetspeedDecorator extends SkillDecorator {
    public SetspeedDecorator(Character character) {
        super(character);
    }

    @Override
    public void attack() {
        super.attack();
        System.out.print("集速手雷辅助!");
    }
}

⑥爆破飞弹技能

public class ExplosiveMissileDecorator extends SkillDecorator {
    public ExplosiveMissileDecorator(Character character) {
        super(character);
    }

    @Override
    public void attack() {
        super.attack();
        System.out.print("爆破飞弹辅助!");
    }
}

⑦客户端

public class Client {
    public static void main(String[] args){
        //需要装饰的BillRizer
        BillRizer billRizer=new BillRizer();
        //使用G5手雷辅助
        G5GrenadeDecorator g5GrenadeDecorator=new G5GrenadeDecorator(billRizer);
        g5GrenadeDecorator.attack();
    
        //使用G5手雷+集速手雷+爆破飞弹辅助
        SetspeedDecorator setspeedDecorator=new SetspeedDecorator(g5GrenadeDecorator);
        ExplosiveMissileDecorator explosiveMissileDecorator=new ExplosiveMissileDecorator(setspeedDecorator);
        explosiveMissileDecorator.attack();
    }
}

输出结果:

①散弹枪进行扫射!G5手雷辅助攻击!
②散弹枪进行扫射!G5手雷辅助攻击!集速手雷辅助!爆破飞弹辅助!

把比尔·雷泽的技能介绍一番,大家会发现原来这个看似粗狂的大汉真的霸气十足啊,有资格看你不爽就来一句“想挑战我,随时奉陪!一颗不够,给你来三颗”。

三、总结分析

  • 优点:
    ①装饰类和被装饰类可以独立发展,而不会相互耦合。Component类无须知道Decorator类,而Decorator也不用知道具体的构件,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。
    ②装饰模式是继承关系的一个替代方案。装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。
    ③通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。

  • 缺点:
    ①这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
    ②使用装饰模式进行系统设计时将产生很多小对象,这些装饰类和小对象的产生将增加系统的复杂度,加大学习与理解的难度。

看到装饰模式很多小伙伴会发现跟代理模式很相似,下一篇小Y会对这两种模式进行对比,请期待!!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,783评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,360评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,942评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,507评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,324评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,299评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,685评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,358评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,652评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,704评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,465评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,318评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,711评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,991评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,265评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,661评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,864评论 2 335

推荐阅读更多精彩内容

  • (转载)原文地址 在阎宏博士的《JAVA与模式》一书中开头是这样描述装饰(Decorator)模式的: 装饰模式又...
    zjk_00阅读 628评论 0 2
  • 1 场景问题# 1.1 复杂的奖金计算## 考虑这样一个实际应用:就是如何实现灵活的奖金计算。 奖金计算是相对复杂...
    七寸知架构阅读 3,905评论 4 66
  • 当心在泥泞中复活后,我就恋上阳光雨露下的自然美景,迷上了手机咔嚓后的光影回顾。 轻触光滑的屏...
    蕊玉阅读 231评论 0 1
  • 天还是湛蓝 手里握着 一块橡皮 作面对生活的武器 以为脱口的承诺 可以随时 悄悄抹去 云还是蓬松 口袋揣着 一块橡...
    何事乱翻书阅读 120评论 6 5
  • 2017年11月7日 周二 上午和索店长去热力公司解决暖气问题;下午办公室看报表;晚上应酬一老朋友荣调纪委喝得烂醉...
    茶舍花开阅读 249评论 0 1