java设计模式之装饰者模式

一、定义与类型:

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

》提供了比继承更有弹性的替代方案(扩展原有对象功能)

》类型:结构型

二、装饰者——使用场景

生活场景,比如买礼品时,需要礼品和层层包装,包装可以自行选取后的总花销;买早饭,是肉夹馍还是一个肉夹馍再额外加蛋还是火腿时的售价计算;买蛋糕时,不同层次选择的配料不同,如何计算其价格等

程序场景:扩展一个类的功能或给一个类添加附加职责;

                  动态的给一个对象添加功能,这些功能可以再动态的撤销。

三、优点:

》继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能;

    ——注意:继承属于扩展方式之一,但不一定是弹性设计的最佳实现;并且,继承实现扩展功能,需要提前考虑到所有功能,将可能性通过代码对应出来,也就是说在编译时就已经知道可能性。而装饰者模式在编译时并不能确定用户的操作,以及可能性,属于运行期动态添加改变的功能。

》通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果;

》符合开闭原则。使用装饰者模式,可以扩展对象的行为,装饰者和被装饰者可以独立地变化,原有代码不用改变。程序来说,装饰把类中的者模式就是装饰功能移到对象之外,

四、缺点:

》会出现更多的代码,更多的类,增加程序复杂性;

》动态装饰时,多层装饰时会更复杂;装饰者模式会比继承使用的类少,但是使用到的对象会比继承要多。排查问题时会比较困难,复杂性强。

五、装饰者——相关设计模式

》装饰者模式和代理模式:装饰者模式关注于对象动态地添加功能,而代理模式关注于控制对对象的访问,代理模式中的代理类可以对客户隐藏对象的信息,代理模式中通常是在代理类中创建一个对象的实例,而装饰者模式通常是把被装饰对象(也叫做原始对象)作为一个参数传递给装饰类的构造器。

》装饰者模式和适配器模式:都可以叫做包装模式wrapper,而装饰者模式中的包装者和被包装者可以实现相同的接口,或者装饰者是被装饰者的子类,而适配器模式中适配器和被适配者一般不是同一个接口。扩展说,装饰者模式还可以推广为半装饰模式,比如装饰者除了实现和被装饰者同一个接口外,还可以实现其他接口(或者装饰者和被装饰者继承同一个类,但装饰者继承了实现了其他接口),不同的装饰者实现了其他不同的接口,这个可以被称为半装饰模式。

六、代码实践:

示例一:初级版本:

场景:商家卖煎饼,可以搭配不同的辅料,鸡蛋或者煎饼,计算价格,如下:

package com.zxl.design.pattern.structural.decorator.v1;

/**
 * Created by Administrator on 2019/7/20.
 *煎饼类
 */
public class Battercake {
    public String getDesc(){
        return "煎饼";
    }
    public int cost(){
        return 8;
    }
}
package com.zxl.design.pattern.structural.decorator.v1;

/**
 * Created by Administrator on 2019/7/20.
 * 装饰者:鸡蛋
 */
public class BattercakewithEgg extends Battercake{
    public String getDesc(){
        return super.getDesc()+"加一个鸡蛋";
    }
    public int cost(){
        return super.cost()+1;
    }
}
package com.zxl.design.pattern.structural.decorator.v1;

/**
 * Created by Administrator on 2019/7/20.
 * 装饰者:鸡蛋和香肠
 */
public class BattercakewithEggSausage extends BattercakewithEgg{
    public String getDesc(){
        return super.getDesc()+"加一个香肠";
    }
    public int cost(){
        return super.cost()+2;
    }
}
package com.zxl.design.pattern.structural.decorator.v1;

/**
 * Created by Administrator on 2019/7/20.
 */
public class Test {
    public static void main(String[] args) {
        客户需要一个普通煎饼
        Battercake battercake = new Battercake();
        System.out.println(battercake.getDesc()+"销售价格:"+battercake.cost());
        客户需要一个带鸡蛋的煎饼
        BattercakewithEgg battercakewithEgg = new BattercakewithEgg();
        System.out.println(battercakewithEgg.getDesc()+"销售价格:"+battercakewithEgg.cost());
        客户需要一个带鸡蛋和香肠的煎饼
        BattercakewithEggSausage battercakewithEggSausage = new BattercakewithEggSausage();
        System.out.println(battercakewithEggSausage.getDesc()+"销售价格:"+battercakewithEggSausage.cost());
    }
}
"D:\Program Files\Java\jdk1.8.0_102\bin\java" "-javaagent:D:\InteliijIDea\IntelliJ IDEA 2017.1.4\lib\idea_rt.jar=51497:D:\InteliijIDea\IntelliJ IDEA 2017.1.4\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\Java\jdk1.8.0_102\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\rt.jar;C:\Users\Administrator\Desktop\gson-master\gson-master\DesignMode\target\classes" com.zxl.design.pattern.structural.decorator.v1.Test
煎饼销售价格:8
煎饼加一个鸡蛋销售价格:9
煎饼加一个鸡蛋加一个香肠销售价格:11

java设计模式之装饰者模式_第1张图片

运行结果如上,满足基本要求,但是可以看到,如果辅料不一样,用户可能还需要2个鸡蛋加一个煎饼,那如上就无法实现,怎么办呢?

看下面的优化升级,v2版本:

package com.zxl.design.pattern.structural.decorator.decorator.v2;

/**
 * Created by Administrator on 2019/7/20.
 */
public abstract class ABattercake {
    public abstract String getDesc();

    public abstract int cost();

}
package com.zxl.design.pattern.structural.decorator.decorator.v2;

/**
 * Created by Administrator on 2019/7/20.
 */
public class Battercake extends ABattercake{
    public String getDesc() {
        return "煎饼";
    }
    public int cost() {
        return 8;
    }
}

 

package com.zxl.design.pattern.structural.decorator.decorator.v2;

/**
 * Created by Administrator on 2019/7/20.
 */
public class AbstractDecorator extends ABattercake{
    private ABattercake aBattercake;
    public AbstractDecorator(ABattercake aBattercake){
        this.aBattercake = aBattercake;
    }
    public String getDesc() {
        return this.aBattercake.getDesc();
    }

    public int cost() {
        return this.aBattercake.cost();
    }
}
package com.zxl.design.pattern.structural.decorator.decorator.v2;

/**
 * Created by Administrator on 2019/7/20.
 */
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;
    }
}
package com.zxl.design.pattern.structural.decorator.decorator.v2;

/**
 * Created by Administrator on 2019/7/20.
 */
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;
    }
}
package com.zxl.design.pattern.structural.decorator.decorator.v2;

/**
 * Created by Administrator on 2019/7/20.
 */
public class Test {
    public static void main(String[] args) {
        ABattercake aBattercake;
        aBattercake = new Battercake();
        aBattercake = new EggDecorator(aBattercake);
        aBattercake = new EggDecorator(aBattercake);
        aBattercake = new SausageDecorator(aBattercake);
        System.out.println(aBattercake.getDesc()+"销售价格:"+aBattercake.cost());

    }
}
煎饼加一个鸡蛋加一个鸡蛋加一个香肠销售价格:12

Process finished with exit code 0

java设计模式之装饰者模式_第2张图片

运行结果和UML图如上

如上v2版本,程序更加具备可扩展性,可以根据用户的需求轻松调整。

注:如上UML图中11 表示一个抽象类中有一个抽象的煎饼对象。

扩展:

如上,抽象的装饰类AbstractDecrator类中如果定义为抽象类,其中定义一个抽象的doSomething()方法,

则装饰者的具体实现类,可以根据自己的需求进行适当地扩充功能。如上即为半装饰模式。

七、装饰者模式源码解析:

1、jdk中,最明显的是其中的 IO流方面的内容,比如reader类,扩展有bufferedReader。

    还有inputStream 相关的,对应的有输出bufferdWritter  outputstream等等。

java设计模式之装饰者模式_第3张图片

 2、在Spring框架中,有个处理缓存和同步事务相关的类TransactionAwareCacheDecorator。该类主要是出来spring中缓存和同步处理级别相关的问题

3、在spring框架中SessionRepositoryRequestWrapper(HttpServelet httpServelet)方法

java设计模式之装饰者模式_第4张图片

4、mybatis中装饰者模式的使用 ,比如Cache 相关的一些类。

你可能感兴趣的:(设计模式,java,计算机原理)