写给新人的设计模式——装饰者

装饰者模式允许为一个组件(component)添加不同的装饰者(decorator),从而在不改变代码的情况下更改组件的功能。这是一种继承的替换方案,我们可以使用装饰者模式对某个组件进行不断的扩充,从而拓展他的功能。

遵循的设计原则

  1. 面相接口编程:
    装饰者模式中的抽象组件和抽象装饰者,都是将我们需要加强的方法拿出来,放在接口之中,这样我们在使用的时候会更加灵活且耦合度更低
  2. 封装变化:
    装饰者模式将我们需要加强的方法放入接口之中,这样我们在使用的时候不会影响到被封装的部分
    3.开闭原则:
    对扩展开放,对修改关闭。在装饰者模式中,因为所有的封装者都继承自component,每当有新的装饰者出现,他会将之前的decorator+component当成为一个component 来看待,这时候除了接口中暴露出来的方法外,其他的部分已经被封装了起来。

如何实现

装饰者模式一共由四部分组成
1.抽象组件component,这是一个超类(抽象类或者接口),我们需要不断对这个接口中的方法进行强化和拓展。
2.具体组件concreteComponent, 这是超类的具体实现,也被成为被装饰者(decorated object), 即我们要装饰的类。
3.抽象装饰者decorator, 这是所有装饰者的抽象(超类),里面声明了我们需要加强和拓展的方法。他是compoent的子类型(继承/实现了compoent抽象类/接口)
4.具体装饰者concreteDecorator, 这是装饰者的实例,装饰者们持有具体组件的引用,并且对于需要加强的的内容有自己的实现。

装饰者模式,是的,还是网图。。

一句提醒

装饰者模式加强的并不是具体组件 ConcreteComponent, 而是compoent接口中暴露出的方法。

实战演示

/**
 * Created by LeafEater on 2017/2/18.
 * 需求:要求为一家煎饼店做一个点餐系统
 * 煎饼类型: 杂粮煎饼 6元  白面煎饼 5元
 * 加料: 辣条 1元 鸡蛋 1元 火腿 2元
 */
public class OrderSystem {
    public static void main(String[] args) {
        Pancakes pancakes = new MixedPancakes();
        pancakes = new Ham(pancakes);
        pancakes = new Egg(pancakes);
        Pancakes pancakes1 = new Latiao(new Egg(new FlourPancakes()));
        System.out.println("订单:" + pancakes.getDescription());
        System.out.println("价格:" + pancakes.cost());
        System.out.println("订单:" + pancakes1.getDescription());
        System.out.println("价格:" + pancakes1.cost());
    }
}

interface Pancakes {
    public abstract String getDescription();

    public abstract int cost();
}

abstract class Seasoning implements Pancakes {
    @Override
    public abstract String getDescription();
}

class Ham extends Seasoning {

    Pancakes pancakes;

    public Ham(Pancakes pancakes) {
        this.pancakes = pancakes;
    }

    @Override
    public int cost() {
        return pancakes.cost() + 2;
    }

    @Override
    public String getDescription() {
        return pancakes.getDescription() + "+火腿";
    }

    public void hamState() {
        System.out.println("火腿切碎");
    }

}

class Egg extends Seasoning {

    Pancakes pancakes;

    public Egg(Pancakes pancakes) {
        this.pancakes = pancakes;
    }

    @Override
    public int cost() {
        return pancakes.cost() + 1;
    }

    @Override
    public String getDescription() {
        return pancakes.getDescription() + "+鸡蛋";
    }

    public void eggState() {
        System.out.println("鸡蛋打碎");
    }
}

class Latiao extends Seasoning {

    Pancakes pancakes;

    public Latiao(Pancakes pancakes) {
        this.pancakes = pancakes;
    }

    @Override
    public int cost() {
        return pancakes.cost() + 1;
    }

    @Override
    public String getDescription() {
        return pancakes.getDescription() + "+辣条";
    }
}

class MixedPancakes implements Pancakes {

    @Override
    public String getDescription() {
        return "五谷杂粮煎饼";
    }

    @Override
    public int cost() {
        return 6;
    }
}

class FlourPancakes implements Pancakes {

    @Override
    public String getDescription() {
        return "白面煎饼";
    }

    @Override
    public int cost() {
        return 5;
    }
}

再总结一下

装饰者模式在说这样一个场景:随着业务的推进,旧系统中的功能已经不够用了,我们需要在利用旧系统的基础上增加新的功能。
之后再看看我们设计的思路是什么:

  1. 我们需要使用旧系统,那么一定会获得旧系统的引用,所以说在新系统Decorator中,我们引入了旧系统ConcreteComponent的引用
  2. 我们还需要对旧系统做一定程度的改造或者增强,首先分析出旧系统中向外提供的服务,这个服务就是operation();将这种服务抽象成接口之后,再在新系统中实现它,就可以对这个服务进行一些自定义。这时候再看看第一步,我们也拥有旧系统中operation的实现方式,所以就可以在Operation的基础上进行一定的增强。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容