Head First设计模式(阅读笔记)-03.装饰者模式
创始人
2024-02-11 15:24:09
0

星巴兹咖啡

咖啡存在许多的种类,同时也有不同的调料。此时用户可以单点咖啡,也可以点咖啡+调料,请计算费用(这里咖啡和调料都属于Drink的一类)


简单实现


方案1

每出现一种组合就实现一个类,但是每次增加一个咖啡种类或者一个新的调料,类的数量就会倍增,出现类爆炸!


在这里插入图片描述

方案2

具体修改如下:

  • 在基类中加上每个调料的实例变量,并且将其设置为boolean类型表示是否加入
  • 基类的cost方法不再是抽象方法,而是计算加入所有调料后的价格(为什么是计算所有调料???),子类会调用基类的cost方法
  • hasxxxsetxxx方法由于取得和设置调料的bool

这样大大减少了类的数量,但是该方案会出现以下问题:

  • 调整价钱就要修改代码
  • 增加或者删除调料种类时,就要加上新方法并且修改基类的cost方法
  • 某些新饮料(子类)并不需要某些调料,但是仍要继承这些不需要的方法,比如hashSoy

在这里插入图片描述

public class Drink{String desc;// mikeCost、soyCost的实例变量// mike、soy的getter和setter方法public double cost(){float cost = 0.0;if(hasMilk()){cost += milkCost;}if(hasSoy()){cost += soyCost;}return cost;}
}
public class DarkRoast extends Drink{public DarkRoast(){desc = "好喝";}public double cost(){return 2.0 + super.cost();}
}

两个设计原则


  • 利用组合和委托代替继承:
    • 继承设计子类的行为是在编译时静态决定(即所有子类都会继承到相同的行为),而组合扩展对象行为时可以在运行时动态地扩展
    • 通过动态组合对象可以在不修改代码的前提下添加新功能(下面提到的开闭原则)
  • 尽量遵循开闭原则:
    • 类应该对扩展开发,对修改关闭
    • 不需要每个地方都遵循该原则,因为会让代码变得复杂

装饰者模式


什么是装饰者模式?

假设需要一杯摩卡(Mocha)+奶泡(whip)的深焙咖啡(DarkRoast),具体做法和计算价格的过程如下:

  • 拿到一个DarkRoast对象
  • 使用Mocha对象装饰它
  • 使用Whip对象装饰它
  • 调用cost方法,并依赖委托将调料价钱加上

在这里插入图片描述


  • 装饰者可以在被装饰者的行为前/后加上自己的行为(Whip是装饰者,则Mocha是被装饰者,其他依次类推)

  • 装饰者模式可以动态将责任附加到对象上,即扩展功能时更具弹性

  • 装饰者和被装饰者具有相同的父类(因为装饰者可能变为被装饰者,被装饰者也可能变为装饰者)

代码实现


// 需要被继承的公共父类
public abstract class Drink{String desc = "Unknown";public String getDesc(){return desc;}public abstract double cost();
}// 抽象装饰者类(目的在于让装饰者类必须实现getDesc方法)
public abstract class CondimentDecorator extends Drink{public abstract String getDesc();
}// Espresso类,即被装饰者类
public class Soy extends Drink{public Soy(){desc = "Soy"}public double cost(){return 2.0;}
}// Mocha类,即装饰者类
public class Mochas extends CondimentDecorator{Drink drink;  // 组合public Mochas(Drink drink){this.drink = drink;}public String getDesc(){return drink.getDesc() + ", Mocha";}public double cost(){// 1.0是Mocha自己的价格return 1.0 + drink.cost();}
}// 测试
public class CoffeeStore{public static void main(String[] args){// 点一杯加了豆浆的摩卡Drink soy = new Soy();Drink Mocha = new Mocha(espresso);}
}

Java I/O

Java I/O类中,同样使用了装饰者模式,但是也是有缺点的,比如会出现大量的小类

在这里插入图片描述


编写自己的Java I/O装饰者

编写一个装饰者,把输入流中的大写都转为小写


import java.io.*;
// FilterInputStream是抽象装饰者
public class LowerCaseInputStream extends FilterInputStream{public LowerCaseInputStream(InputStream in){super(in);}// 针对字节public int read() throws IOException{int c = super.read();return (c == -1 ? c : Character.toLowerCase((char)c));}// 针对字节数组public int read(byte[] b, int offset, int len) throws IOException{int result = super.read(b, offset, len);for(itn i = offset; i < offset + result; i++){b[i] = (byte)Character.toLowerCase((char)b[i]);}return result;}
}// 测试
public class InputTest{public static void main(String[] args) throws IOException{int c;try{// 先用BufferdInputStream修饰FileInputStream// 再用LowerCaseInputStream修饰BufferdInputStreamInputStream in = new LowerCaseInputStream(new BufferdInputStream(new FileInputStream("test.txt")));while((c = in.read()) >= 0){System.out.print((char)c);}in.close();}catch(IOException e){e.printStackTrace();}}
}

参考

Head First 设计模式-装饰者模式

相关内容

热门资讯

60年变化藏在孩子们的课堂里   2024年,那曲市色尼区第二小学学生在学习计算机知识。  上世纪80年代,那曲县(色尼区)完全小...
​持续经营假设对企业财务核算意... 持续经营假设对企业财务核算意味着什么持续经营是指企业在可预见的未来,将按照当前的规模和状态持续运营,...
河南周口一妇产科主任遭“网暴”... 据津云新闻报道,8月4日,多个社交媒体账号发布视频称“周口市第六人民医院妇产科主任邵某某因长期遭受网...
年中经济观察 | 电商成为农民...   央视网消息:最新数据显示,今年上半年,我国农产品电商交易额增长17.2%。随着互联网的普及,农村...
不满欧美贸易协议,德财长:我们...   新华社北京8月5日电 德国副总理兼财政部长克林拜尔4日在华盛顿表示,欧盟在与美国的贸易谈判中表现...
何以中国 | 暑期热潮带火天津...   暑期来临,天津的相声市场迎来客流高峰,吸引了大量来自全国各地的游客前来感受这项非遗艺术的独特魅力...
夜间经济,让灯火更亮(大数据观...   数据来源:文化和旅游部、中国旅游研究院  8月2日,市民游客在重庆南岸区长嘉汇购物公园观看无人机...
关于下半年经济工作 国务院多部...   7月31日国务院常务会议强调,要锚定全年发展目标任务,加力提升宏观政策效能,持续攻坚破解难题,下...
检察机关依法对谭瑞松涉嫌贪污、...   新华社北京8月5日电 记者5日从最高人民检察院获悉,中国航空工业集团有限公司原党组书记、董事长谭...
俄自杀式无人机打击乌战车:弹药... 近日,在顿涅茨克方向,俄军使用自杀式FPV无人机打击乌军的BMP-2步兵战车,无人机发射弹药贯穿乌军...