Head First设计模式(阅读笔记)-03.装饰者模式

news2024/11/16 9:47:57

星巴兹咖啡

咖啡存在许多的种类,同时也有不同的调料。此时用户可以单点咖啡,也可以点咖啡+调料,请计算费用(这里咖啡和调料都属于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修饰BufferdInputStream
            InputStream 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 设计模式-装饰者模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/31642.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Centos7通过SSH使用密钥实现免密登录

Centos7通过SSH使用密钥实现免密登录 日常开发中,难免会有登录服务器的操作,而通过ssh方式登录无疑是比较方便的一种方式。 如果登录较频繁,使用密钥实现免密登录无疑更是方便中的方便。因此本文就简单说一说如何实现免密登录。一、安装配置ssh服务 默认情况下Centos7是安装…

推荐一款制作精良、功能强大、毫秒级精度的定时任务执行软件

目录 一、定时执行专家 - 功能详细 二、定时执行专家 - 最新版下载 三、定时执行专家 - 更新日志 四、关键字/Keyword 一、定时执行专家 - 功能详细 1、支持多种触发方式&#xff08;定时方式&#xff09;&#xff1a;倒计时执行、持续执行、键盘鼠标空闲指定时长时执行、…

了解的Java泛型

作者&#xff1a;~小明学编程 文章专栏&#xff1a;JavaSE基础 格言&#xff1a;目之所及皆为回忆&#xff0c;心之所想皆为过往 目录 前言 什么是泛型 为什么要引入泛型 使用泛型 裸类型 泛型类的定义 类型擦除 通配符 什么是通配符 通配符的上下界 通配符的使用 …

Cookie和Session的工作流程以及Servlet中与之相关的API

目录 一、认识Cookie和Session 1、Cookie 2、Session 二、Cookie和Session的工作流程 三、Servlet中与Cookie和Session相关的API 1、HttpServletRequest类中的相关方法 2、HttpServletResponse类中的相关方法 3、HttpSession类中的相关方法 4、Cookie类中的相关方法 …

常用的框架技术-10 Spring Security Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录1.Spring Security简介1.1 Spring Security概述1.2 Spring Security历史发展1.3 产品的对比1.3.1 Spring Security1.3.2 Shiro1.4 Spring Security 核心类1.4.1 Auth…

既然有了ES,为何还用ClickHouse——从原理万字总结ClickHouse为何这么快

通过了解 CH 的几大特性了解千亿级企业 ClickHouse 实时处理引擎架构设计、核心技术设计、运行机理全流程。 文章目录1 初始 ClickHouse1.1 什么是 ClickHouse1.2 ClickHouse 的优缺点1.3 谁在用 ClickHouse3 数据引擎3.1 库引擎3.2 表引擎3.3 MergeTree 引擎4 工作原理4.1 数据…

浙大MBA经验分享:在工作生活的缝隙中奋勇上岸

非常高兴可以为大家分享我的浙大MBA备考经验&#xff01;首先针对我的背景简要介绍一下&#xff0c;我本科毕业于省内的普通大学浙江理工大学&#xff0c;学的是设计专业&#xff0c;就业于一家外企公司。在2022年的联考中获得了综合133&#xff0c;英语75&#xff0c;总分是20…

一个简单的音乐网站设计与实现(HTML+CSS)

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 音乐网页设计 | 仿网易云音乐 | 各大音乐官网网页 | 明星音乐演唱会主题 | 爵士乐音乐 | 民族音乐 | 等网站的设计与制作 | HTML期末大学生网页设计作…

常见集群算法解析

Gossip协议 Gossip协议简介 定义 Gossip protocol&#xff0c;又叫 Epidemic Protocol &#xff08;流行病协议&#xff09;&#xff0c;也叫“流言算法” 、 “疫情传播算法”等。其名称已经形象的说明了算法的原理和工作方式 应用场景 分布式网络&#xff0c;无集中管理节…

同花顺l2数据接口的委托队列是什么?

我们都知道股票交易时有买方也有卖方&#xff0c;“买一”通俗理解就是此刻“买”价最“高”即第一的委托集合&#xff0c;卖一则是“卖”价最低的委托集合。 “一”并非指一笔委托或一手股票&#xff0c;它的背后是有多笔报价相同的买入或卖出委托组成&#xff0c;可能是主力…

cesium火箭发射,模型控制,模型动画,模型移动

起因&#xff1a;最近想做模型的动画&#xff0c;结果上网查资料&#xff0c;看到网上好多对于模型控制的文章都有限制。决定还是自己研究下。欢迎大家一起探讨&#xff0c;评论留言。 效果 火箭全部代码在最后 起步 模型控制&#xff0c;第一步当然是需要一个合适的模型&#…

链动2+1模式是否合法合规?它涉及多级传销吗?

根据国家《禁止传销条例》第2条规定&#xff0c;传销是指组织者或者经营者发展人员&#xff0c;通过对被发展人员以其直接或者间接发展的人员数量或者销售业绩为依据计算和给付报酬&#xff0c;或者要求被发展人员以交纳一定费用为条件取得加入资格等方式牟取非法利益&#xff…

【多线程】Thread的interrupt()

一、前言 如果子线程执行完毕终止状态&#xff0c;主线程再去调用interrupt()有什么效果&#xff1f;如果子线程还在执行过程中&#xff0c;主线程调用interrupt()有什么结果&#xff1f; 二、模拟实验 1、模拟子线程执行完毕再调用interrupt() ​ public class Test {publi…

2023年天津美术学院专升本报名考试须知

天津美术学院2023年高职升本科报考须知&#xff08;一&#xff09;专业考试1.报名方法&#xff1a; ①网上报名及缴费&#xff1a; 我校采取网上报名的方式,考生于2022年12月份&#xff08;具体时间关注公众号“高职接本科”另行公告&#xff09;(10:00-22:00)登录网站(网址&am…

web前端期末大作业 html+css学生心理 7页主题网页设计

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 家 | HTML期末大学生网页设计作业 HTML&#xff1a;结构 CSS&#xff1a;样式 在操作方面上运用了html5和css3&#xff0c; 采用了divcss结构、表单、…

Oculus Deeplink

DeepLink 初始化 platform sdk 后设置 应用启动回调判断应用打开的方式发起应用跳转 接收应用跳转 GroupPresence 本文档基于 GroupPresenceSample 脚本逻辑编写&#xff0c;展示通过群组状态发起用户邀请&#xff0c;以及响应对应回调。参考 Oculus 工程 SharedSpaces 使…

【安装教程】vscode安装教程(超详细)

Visual Studio Code&#xff08;简称 VSCode&#xff09;是一款由微软开发且跨平台的免费源代码编辑器。该软件支持语法高亮、代码自动补全、代码重构功能&#xff0c;并且内置了命令行工具和 Git版本控制系统。用户可以更改主题和键盘快捷方式实现个性化设置&#xff0c;也可以…

想裁剪视频时长,用电脑怎么裁剪视频时长

大家有没有碰到过这种一种情况&#xff0c;就是我们在社交平台上发布视频时&#xff0c;会因为视频时长过长这个问题而导致视频发布失败。那我们要怎么处理这个问题呢&#xff1f;其实我们可以使用一些剪辑软件&#xff0c;将视频裁剪&#xff0c;只截取视频里面较为精彩的部分…

hadoop集群安装(三):创建同步工具并安装jdk

文章目录说明分享环境创建同步工具编写脚本设置为系统命令安装jdk总结说明 搭建好集群虚拟机&#xff0c;新建同步工具并安装jdk&#xff0c;同步工具方便管理集群&#xff0c;某些操作和一条命令&#xff0c;同步所有节点&#xff0c;增加集群操作效率。 分享 大数据博客列表…

组件之间通过bus中央事件总线进行通信

案例完整代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widt…