跟萌新一起学设计模式(七)之装饰者模式

**

设计模式(七)之装饰者模式

**

  • 案例说明

  假设我们去一家卖电脑的店买电脑,店里面有戴尔电脑、联想电脑、惠普电脑,这三种电脑本身的价格都是只包括主机和屏幕,如果要买鼠标、键盘、耳机等配件需要另外加钱,如果我们要计算每种组合的价钱,用传统写法的话那就要定义很多类了,一旦要增加一种电脑的品牌或者是一种电脑配件,那类的数量就会变得极其庞大,这里我们只列出电脑+其中一种配件的组合情况来稍微感受一下传统写法可能会造成的“类爆炸”情况:
在这里插入图片描述
  可以看出,单单是电脑+一种配件的组合情况就要建这么多的类,下面是模拟传统写法的客户端调用,客户端也就是电脑店。

public class Client {
    public static void main(String[] args) {
        Computer computer = null;
        computer = new DellComputer();
        System.out.println(computer.cost());

        computer = new HPHeadSet();
        System.out.println(computer.cost());

        computer = new LenovoKeyBoard();
        System.out.println(computer.cost());
    }
}

  测试

D:\jdk8\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=58267:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath D:\jdk8\jre\lib\charsets.jar;D:\jdk8\jre\lib\deploy.jar;D:\jdk8\jre\lib\ext\access-bridge-64.jar;D:\jdk8\jre\lib\ext\cldrdata.jar;D:\jdk8\jre\lib\ext\dnsns.jar;D:\jdk8\jre\lib\ext\jaccess.jar;D:\jdk8\jre\lib\ext\jfxrt.jar;D:\jdk8\jre\lib\ext\localedata.jar;D:\jdk8\jre\lib\ext\nashorn.jar;D:\jdk8\jre\lib\ext\sunec.jar;D:\jdk8\jre\lib\ext\sunjce_provider.jar;D:\jdk8\jre\lib\ext\sunmscapi.jar;D:\jdk8\jre\lib\ext\sunpkcs11.jar;D:\jdk8\jre\lib\ext\zipfs.jar;D:\jdk8\jre\lib\javaws.jar;D:\jdk8\jre\lib\jce.jar;D:\jdk8\jre\lib\jfr.jar;D:\jdk8\jre\lib\jfxswt.jar;D:\jdk8\jre\lib\jsse.jar;D:\jdk8\jre\lib\management-agent.jar;D:\jdk8\jre\lib\plugin.jar;D:\jdk8\jre\lib\resources.jar;D:\jdk8\jre\lib\rt.jar;D:\ideaworkspace\design_pattern\design\target\classes;D:\dev_tools\repository\org\projectlombok\lombok\1.16.10\lombok-1.16.10.jar com.wd.decorator.none.computer.Client
Dell 40004000
HPHeadSet 30803080
LenovoKeyBoard 51005100

Process finished with exit code 0

  我们对上面的设计做一点改造,首先电脑及电脑的具体品牌我们放一起,电脑的配件我们抽离出来放另一边,然后将电脑品牌组合到配件里面去,确保我们可以随意购买某种电脑品牌的某几种配件。
在这里插入图片描述
  电脑抽象类

@Data
public abstract class Computer {

    private String description;

    public abstract BigDecimal cost();
}

  电脑具体的子类

public class DellComputer extends Computer{
    public DellComputer() {
        setDescription("DellComputer");
    }

    @Override
    public BigDecimal cost() {
        // 戴尔电脑本身的价格是4000元
        return new BigDecimal(4000.0);
    }
}
public class HPComputer extends Computer{
    public HPComputer() {
        setDescription("HPComputer");
    }

    @Override
    public BigDecimal cost() {
        // 惠普电脑本身的价格是3000元
        return new BigDecimal(3000.0);
    }
}
public class LenovoComputer extends Computer{
    public LenovoComputer() {
        setDescription("LenovoComputer");
    }

    @Override
    public BigDecimal cost() {
        // 联想电脑本身的价格是4000元
        return new BigDecimal(5000.0);
    }
}

  电脑配件总类,即装饰者类。单独实例化时因为没有具体的配件,所以返回的是电脑本身的价格。

public class Decorator extends Computer{

    private Computer computer;

    public Decorator(Computer computer){
        this.computer = computer;
    }

    @Override
    public String getDescription() {
        return computer.getDescription() + " 配件" + super.getDescription();
    }

    @Override
    public BigDecimal cost() {
        // 返回的是没有加任何配件的电脑价格
        return computer.cost();
    }
}

  电脑配件中的耳机类,继承了配件的总类,重写了cost方法,返回的是之前的累加价格加上耳机本身的80元。

public class HeadSet extends Decorator{

    public HeadSet(Computer computer) {
        super(computer);
        setDescription("HeadSet");
    }

    @Override
    public BigDecimal cost() {
        // 返回的是上次累加的价格加上耳机本身80元的总价格
        return super.cost().add(new BigDecimal(80.0));
    }
}

  电脑配件中的键盘类,继承了配件的总类,重写了cost方法,返回的是之前的累加价格加上键盘本身的100元。

public class KeyBoard extends Decorator{

    public KeyBoard(Computer computer) {
        super(computer);
        setDescription("KeyBoard");
    }

    @Override
    public BigDecimal cost() {
        // 返回的是上次累加的价格加上键盘本身100元的总价格
        return super.cost().add(new BigDecimal(100.0));
    }
}

  电脑配件中的鼠标类,继承了配件的总类,重写了cost方法,返回的是之前的累加价格加上鼠标本身的50元。

public class Mouse extends Decorator{

    public Mouse(Computer computer) {
        super(computer);
        setDescription("Mouse");
    }

    @Override
    public BigDecimal cost() {
        // 返回的是上次累加的价格加上鼠标本身50元的总价格
        return super.cost().add(new BigDecimal(50.0));
    }
}

  客户端模拟在电脑店卖东西

  先买一台惠普电脑,不要配件:

public class Client {
    public static void main(String[] args) {
        Decorator dec = null;
        Computer computer = null;
        // 买一台惠普电脑
        computer = new HPComputer();
        dec = new Decorator(computer);
       System.out.println("买的电脑和配件包括:电脑" + dec.getDescription() + ";共花费:" + dec.cost() + "元");
    }
}

  测试:

D:\jdk8\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=60406:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath D:\jdk8\jre\lib\charsets.jar;D:\jdk8\jre\lib\deploy.jar;D:\jdk8\jre\lib\ext\access-bridge-64.jar;D:\jdk8\jre\lib\ext\cldrdata.jar;D:\jdk8\jre\lib\ext\dnsns.jar;D:\jdk8\jre\lib\ext\jaccess.jar;D:\jdk8\jre\lib\ext\jfxrt.jar;D:\jdk8\jre\lib\ext\localedata.jar;D:\jdk8\jre\lib\ext\nashorn.jar;D:\jdk8\jre\lib\ext\sunec.jar;D:\jdk8\jre\lib\ext\sunjce_provider.jar;D:\jdk8\jre\lib\ext\sunmscapi.jar;D:\jdk8\jre\lib\ext\sunpkcs11.jar;D:\jdk8\jre\lib\ext\zipfs.jar;D:\jdk8\jre\lib\javaws.jar;D:\jdk8\jre\lib\jce.jar;D:\jdk8\jre\lib\jfr.jar;D:\jdk8\jre\lib\jfxswt.jar;D:\jdk8\jre\lib\jsse.jar;D:\jdk8\jre\lib\management-agent.jar;D:\jdk8\jre\lib\plugin.jar;D:\jdk8\jre\lib\resources.jar;D:\jdk8\jre\lib\rt.jar;D:\ideaworkspace\design_pattern\design\target\classes;D:\dev_tools\repository\org\projectlombok\lombok\1.16.10\lombok-1.16.10.jar com.wd.decorator.one.Client
买的电脑和配件包括:电脑HPComputer 配件null;共花费:3000元

Process finished with exit code 0

  买一台惠普电脑的基础上再买一个鼠标:

public class Client {
    public static void main(String[] args) {
        Decorator dec = null;
        Computer computer = null;
        // 买一台惠普电脑
        computer = new HPComputer();
        dec = new Mouse(computer);
        System.out.println("买的电脑和配件包括:电脑" + dec.getDescription() + ";共花费:" + dec.cost() + "元");
    }
}

  测试:

D:\jdk8\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=60455:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath D:\jdk8\jre\lib\charsets.jar;D:\jdk8\jre\lib\deploy.jar;D:\jdk8\jre\lib\ext\access-bridge-64.jar;D:\jdk8\jre\lib\ext\cldrdata.jar;D:\jdk8\jre\lib\ext\dnsns.jar;D:\jdk8\jre\lib\ext\jaccess.jar;D:\jdk8\jre\lib\ext\jfxrt.jar;D:\jdk8\jre\lib\ext\localedata.jar;D:\jdk8\jre\lib\ext\nashorn.jar;D:\jdk8\jre\lib\ext\sunec.jar;D:\jdk8\jre\lib\ext\sunjce_provider.jar;D:\jdk8\jre\lib\ext\sunmscapi.jar;D:\jdk8\jre\lib\ext\sunpkcs11.jar;D:\jdk8\jre\lib\ext\zipfs.jar;D:\jdk8\jre\lib\javaws.jar;D:\jdk8\jre\lib\jce.jar;D:\jdk8\jre\lib\jfr.jar;D:\jdk8\jre\lib\jfxswt.jar;D:\jdk8\jre\lib\jsse.jar;D:\jdk8\jre\lib\management-agent.jar;D:\jdk8\jre\lib\plugin.jar;D:\jdk8\jre\lib\resources.jar;D:\jdk8\jre\lib\rt.jar;D:\ideaworkspace\design_pattern\design\target\classes;D:\dev_tools\repository\org\projectlombok\lombok\1.16.10\lombok-1.16.10.jar com.wd.decorator.one.Client
买的电脑和配件包括:电脑HPComputer 配件Mouse ;共花费:3050元

Process finished with exit code 0

  买一台惠普电脑和一个鼠标的基础上再买一个耳机:

public class Client {
    public static void main(String[] args) {
        Decorator dec = null;
        Computer computer = null;
        // 买一台惠普电脑
        computer = new HPComputer();
        // 买一个鼠标
        dec = new Mouse(computer);
        // 再买一个耳机
        dec = new HeadSet(dec);
        System.out.println("买的电脑和配件包括:电脑" + dec.getDescription() + ";共花费:" + dec.cost() + "元");
    }
}

  测试:

D:\jdk8\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=60482:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath D:\jdk8\jre\lib\charsets.jar;D:\jdk8\jre\lib\deploy.jar;D:\jdk8\jre\lib\ext\access-bridge-64.jar;D:\jdk8\jre\lib\ext\cldrdata.jar;D:\jdk8\jre\lib\ext\dnsns.jar;D:\jdk8\jre\lib\ext\jaccess.jar;D:\jdk8\jre\lib\ext\jfxrt.jar;D:\jdk8\jre\lib\ext\localedata.jar;D:\jdk8\jre\lib\ext\nashorn.jar;D:\jdk8\jre\lib\ext\sunec.jar;D:\jdk8\jre\lib\ext\sunjce_provider.jar;D:\jdk8\jre\lib\ext\sunmscapi.jar;D:\jdk8\jre\lib\ext\sunpkcs11.jar;D:\jdk8\jre\lib\ext\zipfs.jar;D:\jdk8\jre\lib\javaws.jar;D:\jdk8\jre\lib\jce.jar;D:\jdk8\jre\lib\jfr.jar;D:\jdk8\jre\lib\jfxswt.jar;D:\jdk8\jre\lib\jsse.jar;D:\jdk8\jre\lib\management-agent.jar;D:\jdk8\jre\lib\plugin.jar;D:\jdk8\jre\lib\resources.jar;D:\jdk8\jre\lib\rt.jar;D:\ideaworkspace\design_pattern\design\target\classes;D:\dev_tools\repository\org\projectlombok\lombok\1.16.10\lombok-1.16.10.jar com.wd.decorator.one.Client
买的电脑和配件包括:电脑HPComputer 配件Mouse  配件HeadSet ;共花费:3130元

Process finished with exit code 0

  买一台惠普电脑、一个鼠标和一个耳机的基础上再买一个键盘:

public class Client {
    public static void main(String[] args) {
        Decorator dec = null;
        Computer computer = null;
        // 买一台惠普电脑
        computer = new HPComputer();
        // 买一个鼠标
        dec = new Mouse(computer);
        // 再买一个耳机
        dec = new HeadSet(dec);
        // 再买一个键盘
        dec = new KeyBoard(dec);
        System.out.println("买的电脑和配件包括:电脑" + dec.getDescription() + ";共花费:" + dec.cost() + "元");
    }
}

  测试:

D:\jdk8\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=60525:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath D:\jdk8\jre\lib\charsets.jar;D:\jdk8\jre\lib\deploy.jar;D:\jdk8\jre\lib\ext\access-bridge-64.jar;D:\jdk8\jre\lib\ext\cldrdata.jar;D:\jdk8\jre\lib\ext\dnsns.jar;D:\jdk8\jre\lib\ext\jaccess.jar;D:\jdk8\jre\lib\ext\jfxrt.jar;D:\jdk8\jre\lib\ext\localedata.jar;D:\jdk8\jre\lib\ext\nashorn.jar;D:\jdk8\jre\lib\ext\sunec.jar;D:\jdk8\jre\lib\ext\sunjce_provider.jar;D:\jdk8\jre\lib\ext\sunmscapi.jar;D:\jdk8\jre\lib\ext\sunpkcs11.jar;D:\jdk8\jre\lib\ext\zipfs.jar;D:\jdk8\jre\lib\javaws.jar;D:\jdk8\jre\lib\jce.jar;D:\jdk8\jre\lib\jfr.jar;D:\jdk8\jre\lib\jfxswt.jar;D:\jdk8\jre\lib\jsse.jar;D:\jdk8\jre\lib\management-agent.jar;D:\jdk8\jre\lib\plugin.jar;D:\jdk8\jre\lib\resources.jar;D:\jdk8\jre\lib\rt.jar;D:\ideaworkspace\design_pattern\design\target\classes;D:\dev_tools\repository\org\projectlombok\lombok\1.16.10\lombok-1.16.10.jar com.wd.decorator.one.Client
买的电脑和配件包括:电脑HPComputer 配件Mouse  配件HeadSet  配件KeyBoard ;共花费:3230元

Process finished with exit code 0

  买一台惠普电脑、一个鼠标、一个耳机和一个键盘的基础上再买一个键盘:

public class Client {
    public static void main(String[] args) {
        Decorator dec = null;
        Computer computer = null;
        // 买一台惠普电脑
        computer = new HPComputer();
        // 买一个鼠标
        dec = new Mouse(computer);
        // 再买一个耳机
        dec = new HeadSet(dec);
        // 再买一个键盘
        dec = new KeyBoard(dec);
        // 再买一个键盘
        dec = new KeyBoard(dec);
        System.out.println("买的电脑和配件包括:电脑" + dec.getDescription() + ";共花费:" + dec.cost() + "元");
    }
}

  测试:

D:\jdk8\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=60761:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath D:\jdk8\jre\lib\charsets.jar;D:\jdk8\jre\lib\deploy.jar;D:\jdk8\jre\lib\ext\access-bridge-64.jar;D:\jdk8\jre\lib\ext\cldrdata.jar;D:\jdk8\jre\lib\ext\dnsns.jar;D:\jdk8\jre\lib\ext\jaccess.jar;D:\jdk8\jre\lib\ext\jfxrt.jar;D:\jdk8\jre\lib\ext\localedata.jar;D:\jdk8\jre\lib\ext\nashorn.jar;D:\jdk8\jre\lib\ext\sunec.jar;D:\jdk8\jre\lib\ext\sunjce_provider.jar;D:\jdk8\jre\lib\ext\sunmscapi.jar;D:\jdk8\jre\lib\ext\sunpkcs11.jar;D:\jdk8\jre\lib\ext\zipfs.jar;D:\jdk8\jre\lib\javaws.jar;D:\jdk8\jre\lib\jce.jar;D:\jdk8\jre\lib\jfr.jar;D:\jdk8\jre\lib\jfxswt.jar;D:\jdk8\jre\lib\jsse.jar;D:\jdk8\jre\lib\management-agent.jar;D:\jdk8\jre\lib\plugin.jar;D:\jdk8\jre\lib\resources.jar;D:\jdk8\jre\lib\rt.jar;D:\ideaworkspace\design_pattern\design\target\classes;D:\dev_tools\repository\org\projectlombok\lombok\1.16.10\lombok-1.16.10.jar com.wd.decorator.one.Client
买的电脑和配件包括:电脑HPComputer 配件Mouse  配件HeadSet  配件KeyBoard  配件KeyBoard ;共花费:3330元

Process finished with exit code 0
  • 总结
      1、 通过组合而非继承的方式,实现了动态扩展对象的功能的能力。
       2、 有效避免了使用继承的方式扩展对象功能而带来的灵活性差,子类无限制扩张的问题。
      3、 充分利用了继承和组合的长处和短处,在灵活性和扩展性之间找到完美的平衡点。
      4、 装饰者和被装饰者之间虽然都是同一类型,但是它们彼此是完全独立并可以各自独立任意改变的。
      5、 遵守大部分常用设计原则,高内聚、低耦合。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值