继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

【学习笔记】装饰者设计模式

Sivel
关注TA
已关注
手记 16
粉丝 9
获赞 50

装饰者模式

定义:

在不改变原有对象的基础之上,将功能附加到对象上

特点 :

提供了比继承更有弹性的替代方案(扩展语言有对象功能,其实也是建立在继承之上)

类型 :结构型

适用场景

  • 扩展一个类的功能或者给一个类添加附加职责
  • 动态 的给一个对象添加功能,这些功能可以再动态撤销

优点

  • 继承的有力补充,比继承灵活,不改变原有对象的情况下给对象扩展功能。如果需要继承的功能很多,必然会增加很多子类。而且继承需要对继承的功能是可预见的,因为功能在编译的时候就确定了因此是静态的。
    而装饰这是应用层代码动态的加载。
  • 通过不同的装饰类进行排列组合,可以达到更多的效果。
  • 符合开闭原则(换句话说,把类的装饰功能移出去,把类的核心功能和类的装饰功能区分开)

缺点

  • 会出现更多的代码,更多的类,增加程序复杂性(其实更多的类是不一定,因为继承也会有很多类,但是比继承多很多对象,因为装饰类比较相似,因此排查错误会比较费劲)
  • 动态装饰时,多层装饰时会更复杂

相关设计模式

  • 装饰者 和 代理模式
  • 装饰者 和 适配器

具体举例
我们创建一个煎饼类

   //具体描述
    public String getDesc() {

        return "煎饼";
    }
    //获得加个
    public int cost() {
        return 8;
    }
//这时候我们想吃加鸡蛋的煎饼,就创建一个加鸡蛋的类
public class BattercakeWithEgg extends Battercake {
    @Override
    public String getDesc() {
        return super.getDesc() + "加一个鸡蛋";
    }

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

//这时候我们想吃加火腿肠的 就再创建一个加火腿肠的类。
public class BattercakeWithEggSausage extends BattercakeWithEgg {

    @Override
    public String getDesc() {
        return super.getDesc() + "加一根香肠";
    }

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

图片描述

煎饼 销售价格:8
煎饼加一个鸡蛋 销售价格:9
煎饼加一个鸡蛋加一根香肠 销售价格:11

图片描述

      test类想像成我们的应用层代码。通过上面的打印结果我们能看出来,我们吃煎饼想要加的东西都实现了。但是如果现在我想吃一张煎饼加两个鸡蛋加两根香肠,那么就没有办法实现了。我们需要创建新的类去继承,但可以看出弊端我们需要无限的创造。可能正是由于这种场景,使得装饰者模式出现。

装饰者模式

      装饰者模式是需要有四个东西:一个抽象的实体类、一个确定的实体类、一个抽象的装饰者、一个确定的装饰者。

//抽象的实体
public abstract class ABattercake {
    public abstract String getDesc();

    public abstract int cost();
}
//具体的实体
public class Battercake extends ABattercake {

    @Override
    public String getDesc() {

        return "煎饼";
    }

    @Override
    public int cost() {
        return 8;
    }
}
//抽象的的装饰者,当前并不是抽象类。可以变成抽象类,加个抽象方法 比如doSomething()具体需要看业务的实现。比如加鸡蛋需要敲碎壳,加香肠需要撕开包装纸
public class AbstractDecorator extends ABattercake {
    private ABattercake aBattercake;

    public AbstractDecorator(ABattercake aBattercake) {
        this.aBattercake = aBattercake;
    }

    @Override
    public String getDesc() {
        return aBattercake.getDesc();
    }

    @Override
    public int cost() {
        return aBattercake.cost();
    }
}

//鸡蛋装饰
public class EggDecorator extends AbstractDecorator {

    public EggDecorator(ABattercake aBattercake) {
        super(aBattercake);
    }

    @Override
    public String getDesc() {
        return super.getDesc() + "加一个鸡蛋";
    }

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

//香肠装饰
public class SausageDecorator extends AbstractDecorator {
    public SausageDecorator(ABattercake aBattercake) {
        super(aBattercake);
    }

    @Override
    public String getDesc() {
        return super.getDesc() + "加一根香肠";
    }

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

通过上面的代码我们可以看到,我们把抽象的装饰器和具体的实体都继承了抽象的实体,目的是为了将他们通过共同的父类联系起来。而在抽象装饰者中我们通过构造器,以组合的方式来进行使用。

  public AbstractDecorator(ABattercake aBattercake) {
        this.aBattercake = aBattercake;
    }

我们通过调用抽象的装饰者,其实是把这个行为委托给里面的抽象的实体完成的。

图片描述
下面是具体的uml
图片描述

jdk中的装饰者模式

      其实要是但看文章基本用不了几分钟,但是吸收、运用、查资料理解我感觉还是要用一定的时间的。书上说不要为了用设计模式而用设计模式,其实我现在感觉就应该为了用设计模式而用设计模式,我认为这样在初期能够更好的去理解。
图片描述
通过io的uml与之前形成uml,我们可以进行对比着看。inputstream相当于抽象实体类,ByteArrayInputStream、FileInputStream等是具体的实体类,FilterInputStream相当于抽象的装饰者,而且子类则是具体的装饰者。

其中reader,writer也是。但是我还没有验证
图片描述

假如你还有兴趣去一些源码,还有一些:spring中的TransactionAwareCacheDecorator、SessionRepositoryRrequestWrapper, mybatis中的cache包下decorators的包里面。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP