美文网首页
设计模式之——装饰者模式

设计模式之——装饰者模式

作者: FeidianJava | 来源:发表于2018-12-08 22:02 被阅读16次

一、认识装饰者模式

定义:

装饰模式指的是在不必改变原类文件的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。提供了比继承更有弹性的替代方案。

作用:

在不用修改任何底层底层代码的情况下,给对象赋予新的功能。

本章可以称为“给爱用继承的人一个全新的设计眼界”

接下来,我们来看看下面这个例子!

二、咖啡店实例

以下是一家咖啡店最初的类设计。
四种具体的咖啡种类继承抽象类Beverage,并各自实现了其抽象方法cost()。


图片.png

由于咖啡可以加入各种配料,
例如:蒸奶(Steamed Milk)、豆浆(Soy)、 摩卡(Mocha,也就是巧克力风味)或覆盖奶泡。

1)第一次糟糕的尝试如下...

图片.png
他们将每种咖啡与各种配料的各种搭配都设计成了类!?
图片.png
这样给维护带来了大麻烦!
如果某种饮料和配料价格变化,如果添加某种饮料或者配料,都需要更改许多个类的内容!
而且违反了多用组合,少用继承针对接口编程,而不是针对实现编程这两个设计原则!

2)然后,有人提出用实例变量和继承追踪这些调理

图片.png

代码如下

class Beverage{
    String description;
    public static float milkCost = .2f;
    public static float soyCost = .1f;
    public static float mochaCost = .3f;
    public static float whipCost = .4f;
    //各种调料的份数
    int milk,soy,mocha,whip;
    /*为调料设计set和get方法
    ....*/
    boolean hasMilk(){return milk == 0?false:true;}
    boolean hasSoy(){return milk == 0?false:true;}
    boolean hasMocha(){return milk == 0?false:true;}
    boolean hasWhip(){return milk == 0?false:true;}

    public double cost() {
        float condimentCost = 0.0f;
        if (hasMilk()) { condimentCost += milkCost; }
        if (hasSoy()) { condimentCost += soyCost; }
        if (hasMocha()) { condimentCost += mochaCost; }
        if (hasWhip()) { condimentCost += whipCost; }
        return condimentCost;
    }

如果想添加多份配料,也可以调整超类里的cost()方法。

public double cost(){
       return milk*milkCost+soy*soyCost+mocha*mochaCost+whip*whipCost;
   }

还是会存在下列问题
1.当调料价钱改变,我们要改变超类中各配料价格常量的值
2.当添加新调料,我们需要在超类中添加新的变量,需要改变超类中的cost()方法
3.而且,每一种饮料都会拥有每种调料的的实例变量,就会出现第一章中的问题。如果茶饮料里面加上摩卡就会很奇怪,尽管可以设置hasmocha() == false,但是从意义上讲还是很奇怪。

这里咱们要提出又一种设计原则
开放—关闭原则:类应该对扩展开放,对修改关闭。
这样的原则既有弹性可以应对变化,又保证了正确的代码的安全性。

我们的目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配 新的行为。如能实现这样的目标,有什么好处呢?这样的设计具有弹性可以应对改变,可以接受新的功能来应对改变的需求。

3)用装饰者模式解决问题

通过上面两个例子,我们认识到一味继承不能解决所有问题。

这里要采用不一样的做法:我们要以饮料为主体,然后在运行时以调料来“装饰”(decorate)饮料。比方说,如果顾客想要摩卡 和奶泡深焙咖啡,那么,要做的是:
1拿一个深焙咖啡(DarkRoast)对象
2以摩卡(Mocha)对象装饰它
3 以奶泡(Whip)对象装饰它
4 调用cost()方法,将调料的价钱加上去。


图片.png

通过上面的方法,我们了解到装饰者模式的一些特点
1.装饰者和被装饰对象有相同的超类型。
2. 你可以用一个或多个装饰者包装一个对象。
3.既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它。
4. 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
5.对象可以在任何时候被装饰,所以可以在运行时动态地,不限量地用你喜欢的装饰者来装饰对象。
下图为装饰者模式的模型图

图片.png
运用到这家咖啡店就是下图
图片.png
代码实现
public abstract class Beverage {
    String description = "Unknown yet";
    public String getDescription(){return description;}
    public abstract double cost();
}

class DarkRoast extends Beverage {
    public DarkRoast(){description = "DarkRoast";}
    @Override
    public double cost() {
        return 1.2;
    }
}

class HouseBlend extends Beverage{
    public HouseBlend(){description = "House Blend Coffee";}
    @Override
    public double cost() {
        return 1.4;
    }
}

abstract class CondimentDecorator extends Beverage {
    public abstract String getDescription();
}

class Soy extends CondimentDecorator{
    Beverage beverage;
    public Mocha(Beverage beverage){this.beverage = beverage;}
    public String getDescription(){return beverage.getDescription()+",Soy";}
    public double cost(){return 0.1+beverage.cost();}
}

class Mocha extends CondimentDecorator{
    Beverage beverage;
    public Mocha(Beverage beverage){this.beverage = beverage;}
    public String getDescription(){return beverage.getDescription()+",mocha";}
    public double cost(){return 0.3+beverage.cost();}
}

class Whip extends CondimentDecorator{
        Beverage beverage;
    public Whip(Beverage beverage){this.beverage = beverage;}
    public String getDescription(){return beverage.getDescription()+",whip";}
    public double cost(){return 0.4+beverage.cost();}
}

class Milk extends CondimentDecorator{
    Beverage beverage;
    public Milk(Beverage beverage){this.beverage = beverage;}
    public String getDescription(){return beverage.getDescription()+",milk";}
    public double cost(){return 0.2+beverage.cost();}
}
 public class Main {
    public static void main(String[] args) {
        Beverage a = new DarkRoast();
        a = new Milk(a);
        a = new Milk(a);
        a = new Mocha(a);

        Beverage b = new HouseBlend();
        b = new Milk(b);
        b = new Mocha(b);
        b = new Whip(b);

        System.out.println(a.getDescription()+"  "+a.cost()+"$");
        System.out.println(b.getDescription()+"  "+b.cost()+"$");
    }
}

运行结果


图片.png

java.io类

图片.png
同理,输出流的设计也是雷同的。
学习装饰者模式可以帮我们更好地理解流相关的类。

相关文章

  • JavaScript 设计模式核⼼原理与应⽤实践 之 结构型设计

    JavaScript 设计模式核⼼原理与应⽤实践 之 结构型设计模式 装饰器模式,又名装饰者模式。它的定义是“在不...

  • Java设计模式之 —— 装饰者(Decorator) — 点

    Java设计模式之 —— 装饰者(Decorator) — 点炒饭 下面会用做炒饭的例子来描述一下装饰者设计模式,...

  • 设计模式

    设计模式 单例模式、装饰者模式、

  • 设计模式笔记汇总

    目录 设计原则 “依赖倒置”原则 未完待续... 设计模式 设计模式——策略模式 设计模式——装饰者模式 设计模式...

  • java IO 的知识总结

    装饰者模式 因为java的IO是基于装饰者模式设计的,所以要了解掌握IO 必须要先清楚什么事装饰者模式(装饰者模式...

  • 设计模式

    常用的设计模式有,单例设计模式、观察者设计模式、工厂设计模式、装饰设计模式、代理设计模式,模板设计模式等等。 单例...

  • 设计模式之装饰者模式

    如果你没了解过装饰者模式,那么请继续往下看,如果你是老司机,那么,你可以快速往下看。 开始装个13,再进入正文。 ...

  • 设计模式之装饰者模式

    该模式可以避免滥用继承,在使用对象组合的方式,就能做到在运行时装饰类,此后便能在不修改任何底层代码的情况下给对象赋...

  • 设计模式之装饰者模式

    装饰者模式的定义是动态地给一个对象添加一些额外的职责。就增加功能来说,装饰者模式比生成子类更加灵活。 通常给一个对...

  • 设计模式之装饰者模式

    前言: 相信Java开发者在使用java i/o API的时候,对于以下代码写法应该非常熟悉: 在不知道具体设计实...

网友评论

      本文标题:设计模式之——装饰者模式

      本文链接:https://www.haomeiwen.com/subject/mmrqhqtx.html