装饰者模式的应用场景 java装饰者模式

一.背景看一个项目需求:咖啡订购项目。咖啡有很多种:美式、摩卡、意式浓缩咖啡;咖啡配料:牛奶、豆浆、可可。是的,这是必须的。当扩展新的咖啡类型时,它可以很容易地维护。快速算出不同种类的咖啡要多少钱?顾客可以点咖啡,也可以点咖啡+配料。最坏的计划直接想想,它是一...

一.背景

看一个项目需求:咖啡订购项目。

咖啡有很多种:美式、摩卡、意式浓缩咖啡;
咖啡配料:牛奶、豆浆、可可。

是的,这是必须的。当扩展新的咖啡类型时,它可以很容易地维护。快速算出不同种类的咖啡要多少钱?顾客可以点咖啡,也可以点咖啡+配料。

最坏的计划

直接想想,它是一个咖啡基类,然后所有单品和所有组合咖啡都会继承这个基类,每个类都有自己对应的价格。

问题:这么多种咖啡和配料的组合,相当于卖咖啡的一个子类。如果全部实现的话,基本上就是一个完整的安排了,显然又要爆炸了。并且,要扩展,多加一种调料,各种咖啡都要重新清点,重新组合。

改进项目

调味料内置在咖啡基础类中,所以不会造成太多的量。当一个单独的咖啡项目继承了咖啡基类时,它都会有这些调料。同时需要提供相应的方法来计算是否添加了这种调味料。

问题:这种方法虽然改善了类爆炸的问题,但是内置的属性导致了强耦合。一个调料删了怎么办?加个调料?每个类都要改,需要大量维护。

第二,装饰者模型

Decorator模式:动态地给对象附加新的函数,在对象函数扩展方面比继承更灵活。

具体实现如下,如下面的类图所示:

如你所见,装饰器中有一个组件对象,这是核心部分。

也就是说,不是像我们想的那样给单咖啡加调料,反过来想,而是把单咖啡带到调料里,决定怎么处理。

如果有许多ConcreteComponent,你甚至可以添加一个缓冲层。

装饰模式用于解决上述咖啡订单问题。类图设计如下,考虑到具体咖啡项目的类型,增加了一个缓冲层。最基本的抽象类叫做饮料:

其中Drink相当于前面的组件,Coffee是缓冲层,下面的不同Coffee是上面的ConcreteConponent。

成本计算方法由咖啡的正常思维方式改变,在调料。因为成本也在饮料类,所以最后的计算其实就是把之前的成本结果拿来。如果是多种装修工装修,比如一款配料很多的咖啡,其实就是递归思维计算

这样,加一个单品的咖啡,或者加香料,都不用换其他地方。

代码如下,类比很多,但每一个都比较简单:

/* 抽象类Drink,相当于Component; getset方法提供给子类去设置饮品或调料的信息 但是:cost方法留给调料部分实现*/public abstract class Drink { public String description; private float price = 0.0f; //价格方法 public abstract float cost(); public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } public String getDescription() { return description +":"+ price; } public void setDescription(String description) { this.description = description; }}

然后是Coffe缓冲层和下面的实现类,相当于ConcreteComponent:

public class Coffee extends Drink{ @Override public float cost() { return super.getPrice(); }}public class MochaCoffee extends Coffee{ public MochaCoffee() { setDescription(" 摩卡咖啡 "); setPrice(7.0f); }}public class USCoffee extends Coffee{ public USCoffee() { setDescription(" 美式咖啡 "); setPrice(5.0f); }}public class ItalianCoffee extends Coffee { public ItalianCoffee(){ setDescription(" 意大利咖啡 "); setPrice(6.0f); }}

那么装饰核、装饰者、饮料就是继承+组合关系:

/* Decorator,反客为主去拿已经有price的drink,并加上佐料 加佐料的时候是拿去了Drink对象,但是也是给Drink进行*/public class Decorator extends Drink{ private Drink drink; //提供一个构造器 public Decorator(Drink drink){ this.drink = drink; } @Override public float cost() { //计算成本,拿到佐料自己的价格+本来一杯Drink的价格 //这里注意调用的是drink.cost不是drink.getPrice,因为cost才是子类实现的,Drink类的getPrice方法默认是返回0 return super.getPrice() + drink.cost(); } @Override public String getDescription() { //自己的信息+被装饰者coffee的信息 return description + " " + getPrice() + " &&" + drink.getDescription(); }}

以及Decorator的实现类,即ConcreteDecorator:

public class Milk extends Decorator{ public Milk(Drink drink) { super(drink); setDescription(" 牛奶:"); setPrice(1.0f); }}public class Coco extends Decorator{ public Coco(Drink drink) { super(drink); setDescription(" 可可:"); setPrice(2.0f);//调味品价格 }}public class Sugar extends Decorator { public Sugar(Drink drink) { super(drink); setDescription(" 糖:"); setPrice(0.5f); }}

注意,对于具体的装饰者来说,这里体现的是逆向思维。获取饮料对象,并调用父类构造函数获取饮料。然后set和get方法设置调料本身的价格和描述,父类的方法cost会计算价格合成。

drink.cost()中的super.getprice ()+cost()是一个递归的过程。

最后,让我们编写一个客户端测试:

public class Client { public static void ***in(String[] args) { //1.点一个咖啡,用Drink接受,因为还没有完成装饰 Drink usCoffee = new USCoffee(); System.out.println("费用:"+usCoffee.cost()+" 饮品信息:"+usCoffee.getDescription()); //2.加料 usCoffee = new Milk(usCoffee); System.out.println("加奶后:"+usCoffee.cost()+" 饮品信息:"+usCoffee.getDescription()); //3.再加可可 usCoffee = new Coco(usCoffee); System.out.println("加奶和巧克力后:"+usCoffee.cost()+" 饮品信息:"+usCoffee.getDescription()); }}

可以看出,调用时,调料只需在原饮品对象的基础上进行重构,将原饮品装入包装(装饰),最终达到效果。

而且,如果你想扩展一种咖啡或一种调料,只需添加你自己的类。

第三,装饰者模式在JDK的应用

Java IO结构,FilterInputStream是一个装饰器。

2.1 InputStream相当于饮料,是组成部分;
2.2 FileInputStream、StringBufferInputStream和ByteArrayInputStream相当于单咖啡,即ConcreteComponent,是InputStream的子类;
2.3和FilterInputStream相当于Decorator,同时继承和组合了InputStream

2.4 BufferInputStream、DataInputStream和LineNumberInputStream相当于特定的调味料,是FilterInputStream的子类。

当我们通常使用它时:

DataInputStream dataInputStream = new DataInputStream(new FileInputStream("D://test.txt"));

或者:

FileInputStream fi = new FileInputStream("D:\test.txt");DataInputStream dataInputStream = new DataInputStream(fi);//具体操作

里面的fi相当于单杯咖啡,datainputStream只是在里面加了调料。

比较符合上面咖啡的写法。在发表声明时,用InputStream挑选他,您可以:

InputStream fi = new FileInputStream("D:\test.txt");fi = new DataInputStream(fi);//具体操作

感觉一模一样。

本文来自醉红颜投稿,不代表舒华文档立场,如若转载,请注明出处:https://www.chinashuhua.cn/24/621151.html

打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
() 0
上一篇 07-05
下一篇 07-05

相关推荐

  • 装饰者设计模式功能 设计模式装饰模式例子

    装饰模式装饰模式允许新的函数被添加到现有的对象中。它是一种代替继承的技术,通过继承可以扩展一个对象的新功能,而不需要增加子类。用对象的关联关系代替继承关系更加灵活,同时避免了类型系统的快速膨胀。主要角色:组件(Component):组件接口定义了全部组件类和装饰器实

    2023-07-21 02:24:01
    716 0
  • 装饰者模式的应用场景 java装饰者模式

    一.背景看一个项目需求:咖啡订购项目。咖啡有很多种:美式、摩卡、意式浓缩咖啡;咖啡配料:牛奶、豆浆、可可。是的,这是必须的。当扩展新的咖啡类型时,它可以很容易地维护。快速算出不同种类的咖啡要多少钱?顾客可以点咖啡,也可以点咖啡+配料。最坏的计划直接想想,它是一

    2023-07-05 16:22:01
    174 0
  • 橙家装饰怎么样(橙家装饰官网)

    “稍微有点实力的装修公司都标榜自己是互联网家装公司,但真正能做到高效、全包、一站式服务的互联网家装公司并不多。”近期即将入住的长沙新业主王先生,对互联网家装模式有自己独到的见解。在装修之前,他对比了很多入驻长沙的互联网家装企业,从两点分析了他最终选择桔子家

    2023-06-13 17:32:01
    348 0
  • 店面怎么装饰好看 10个常见的店面装饰风格

    随着社会经济的不断发展,现在越来越多的人自己创业,开店就是他们的创业方式之一。开店前必须先装修店铺,那么店铺怎么装修比较好呢?下面我们来看看店面装修的风格和一些店面装修的小技巧。店面装修有哪些风格?1.店面装修有哪些风格——复古风?复古风给人一种怀旧的感觉。

    2023-05-28 12:43:01
    836 0

评论列表

联系我们

在线咨询: QQ交谈

邮件:admin@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信