设计模式之建造者模式(各项装修物料组合套餐选配场景)

前言:
乱码七糟,我时常怀疑这个成语是来形容程序猿的!
无论承接什么样的需求,是不是身边总有那么几个人代码写的烂,但是却时常有测试小姐姐过来聊天(求改bug)、有产品小伙伴送吃的(求写需求)、有业务小妹妹陪着改代码(求上线),直至领导都认为他的工作很重要,而在旁边的你只能蹭点吃的。
一个项目的上线往往要经历业务需求、产品设计、研发实现、测试验证、上线部署到正式开量,而这其中对研发非常重要的一环就是研发实现的过程,又可以包括为;架构选型、功能设计、设计评审、代码实现、代码评审、单测覆盖率检查、编写文档、提交测试。所以在一些流程规范下,其实很难让你随意开发代码。
在这里插入图片描述
玩王者荣耀的时的初始化界面;有三条路、有树木、有野怪、有守卫塔等等,甚至依赖于你的网络情况会控制清晰度。而当你换一个场景进行其他不同模式的选择时,同样会建设道路、树木、野怪等等,但是他们的摆放和大小都有不同。这里就可以用到建造者模式来初始化游戏元素。
这里模拟装修公司对于设计出一些套餐装修服务的场景。
很多装修公司都会给出自家的套餐服务,一般有;欧式豪华、轻奢田园、现代简约等等,而这些套餐的后面是不同的商品的组合。例如;一级&二级吊顶、多乐士涂料、圣象地板、马可波罗地砖等等,按照不同的套餐的价格选取不同的品牌组合,最终再按照装修面积给出一个整体的报价。
在这里插入图片描述
模拟工程中提供了装修中所需要的物料;ceilling(吊顶)、coat(涂料)、floor(地板)、tile(地砖),这么四项内容。
物料接口

package com.lm.design;import java.math.BigDecimal;/*** 装修物料*/
public interface Matter {/*** 场景;地板、地砖、涂料、吊顶*/String scene();/*** 品牌*/String brand();/*** 型号*/String model();/*** 平米报价*/BigDecimal price();/*** 描述*/String desc();}

物料接口提供了基本的信息,以保证所有的装修材料都可以按照统一标准进行获取。
吊顶

package com.lm.design.ceiling;import com.lm.design.Matter;import java.math.BigDecimal;/*** 吊顶* 品牌;装修公司自带* 型号:一级顶*/
public class LevelOneCeiling implements Matter {@Overridepublic String scene() {return "吊顶";}@Overridepublic String brand() {return "装修公司自带";}@Overridepublic String model() {return "一级顶";}@Overridepublic BigDecimal price() {return new BigDecimal(260);}@Overridepublic String desc() {return "造型只做低一级,只有一个层次的吊顶,一般离顶120-150mm";}}
package com.lm.design.ceiling;import com.lm.design.Matter;import java.math.BigDecimal;/*** 吊顶* 品牌;装修公司自带* 型号:二级顶*/
public class LevelTwoCeiling  implements Matter {@Overridepublic String scene() {return "吊顶";}@Overridepublic String brand() {return "装修公司自带";}@Overridepublic String model() {return "二级顶";}@Overridepublic BigDecimal price() {return new BigDecimal(850);}@Overridepublic String desc() {return "两个层次的吊顶,二级吊顶高度一般就往下吊20cm,要是层高很高,也可增加每级的厚度";}}

涂料

package com.lm.design.coat;import com.lm.design.Matter;import java.math.BigDecimal;/*** 涂料* 品牌;多乐士(Dulux)*/
public class DuluxCoat  implements Matter {@Overridepublic String scene() {return "涂料";}public String brand() {return "多乐士(Dulux)";}public String model() {return "第二代";}public BigDecimal price() {return new BigDecimal(719);}public String desc() {return "多乐士是阿克苏诺贝尔旗下的著名建筑装饰油漆品牌,产品畅销于全球100个国家,每年全球有5000万户家庭使用多乐士油漆。";}}
package com.lm.design.coat;import com.lm.design.Matter;import java.math.BigDecimal;/*** 涂料* 品牌;立邦*/
public class LiBangCoat implements Matter {@Overridepublic String scene() {return "涂料";}public String brand() {return "立邦";}public String model() {return "默认级别";}public BigDecimal price() {return new BigDecimal(650);}public String desc() {return "立邦始终以开发绿色产品、注重高科技、高品质为目标,以技术力量不断推进科研和开发,满足消费者需求。";}}

地板

package com.lm.design.floor;import com.lm.design.Matter;import java.math.BigDecimal;/*** 地板* 品牌;德尔(Der)*/
public class DerFloor implements Matter {@Overridepublic String scene() {return "地板";}public String brand() {return "德尔(Der)";}public String model() {return "A+";}public BigDecimal price() {return new BigDecimal(119);}public String desc() {return "DER德尔集团是全球领先的专业木地板制造商,北京2008年奥运会家装和公装地板供应商";}}
package com.lm.design.floor;import com.lm.design.Matter;import java.math.BigDecimal;/*** 地板* 品牌:圣象*/
public class ShengXiangFloor implements Matter {@Overridepublic String scene() {return "地板";}public String brand() {return "圣象";}public String model() {return "一级";}public BigDecimal price() {return new BigDecimal(318);}public String desc() {return "圣象地板是中国地板行业著名品牌。圣象地板拥有中国驰名商标、中国名牌、国家免检、中国环境标志认证等多项荣誉。";}}

地砖

package com.lm.design.tile;import com.lm.design.Matter;import java.math.BigDecimal;/*** 地砖* 品牌:东鹏瓷砖*/
public class DongPengTile implements Matter {@Overridepublic String scene() {return "地砖";}public String brand() {return "东鹏瓷砖";}public String model() {return "10001";}public BigDecimal price() {return new BigDecimal(102);}public String desc() {return "东鹏瓷砖以品质铸就品牌,科技推动品牌,口碑传播品牌为宗旨,2014年品牌价值132.35亿元,位列建陶行业榜首。";}}
package com.lm.design.tile;import com.lm.design.Matter;import java.math.BigDecimal;/*** 地砖* 品牌;马可波罗(MARCO POLO)*/
public class MarcoPoloTile implements Matter {@Overridepublic String scene() {return "地砖";}public String brand() {return "马可波罗(MARCO POLO)";}public String model() {return "缺省";}public BigDecimal price() {return new BigDecimal(140);}public String desc() {return "“马可波罗”品牌诞生于1996年,作为国内最早品牌化的建陶品牌,以“文化陶瓷”占领市场,享有“仿古砖至尊”的美誉。";}}

一坨坨代码实现
我们都会使用这样很直白的方式去把功能实现出来,再通过设计模式去优化完善。这样的代码结构也都是非常简单的,没有复杂的类关系结构,都是直来直去的代码。除了我们经常强调的这样的代码不能很好的扩展外。
测试代码

package com.lm.design;import com.lm.design.ceiling.LevelOneCeiling;
import com.lm.design.ceiling.LevelTwoCeiling;
import com.lm.design.coat.DuluxCoat;
import com.lm.design.coat.LiBangCoat;
import com.lm.design.floor.ShengXiangFloor;
import com.lm.design.tile.DongPengTile;
import com.lm.design.tile.MarcoPoloTile;import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;public class DecorationPackageController {public String getMatterList(BigDecimal area, Integer level) {List<Matter> list = new ArrayList<Matter>(); // 装修清单BigDecimal price = BigDecimal.ZERO;          // 装修价格// 豪华欧式if (1 == level) {LevelTwoCeiling levelTwoCeiling = new LevelTwoCeiling(); // 吊顶,二级顶DuluxCoat duluxCoat = new DuluxCoat();                   // 涂料,多乐士ShengXiangFloor shengXiangFloor = new ShengXiangFloor(); // 地板,圣象list.add(levelTwoCeiling);list.add(duluxCoat);list.add(shengXiangFloor);price = price.add(area.multiply(new BigDecimal("0.2")).multiply(levelTwoCeiling.price()));price = price.add(area.multiply(new BigDecimal("1.4")).multiply(duluxCoat.price()));price = price.add(area.multiply(shengXiangFloor.price()));}// 轻奢田园if (2 == level) {LevelTwoCeiling levelTwoCeiling = new LevelTwoCeiling(); // 吊顶,二级顶LiBangCoat liBangCoat = new LiBangCoat();                // 涂料,立邦MarcoPoloTile marcoPoloTile = new MarcoPoloTile();       // 地砖,马可波罗list.add(levelTwoCeiling);list.add(liBangCoat);list.add(marcoPoloTile);price = price.add(area.multiply(new BigDecimal("0.2")).multiply(levelTwoCeiling.price()));price = price.add(area.multiply(new BigDecimal("1.4")).multiply(liBangCoat.price()));price = price.add(area.multiply(marcoPoloTile.price()));}// 现代简约if (3 == level) {LevelOneCeiling levelOneCeiling = new LevelOneCeiling();  // 吊顶,二级顶LiBangCoat liBangCoat = new LiBangCoat();                 // 涂料,立邦DongPengTile dongPengTile = new DongPengTile();           // 地砖,东鹏list.add(levelOneCeiling);list.add(liBangCoat);list.add(dongPengTile);price = price.add(area.multiply(new BigDecimal("0.2")).multiply(levelOneCeiling.price()));price = price.add(area.multiply(new BigDecimal("1.4")).multiply(liBangCoat.price()));price = price.add(area.multiply(dongPengTile.price()));}StringBuilder detail = new StringBuilder("\r\n-------------------------------------------------------\r\n" +"装修清单" + "\r\n" +"套餐等级:" + level + "\r\n" +"套餐价格:" + price.setScale(2, BigDecimal.ROUND_HALF_UP) + " 元\r\n" +"房屋面积:" + area.doubleValue() + " 平米\r\n" +"材料清单:\r\n");for (Matter matter: list) {detail.append(matter.scene()).append(":").append(matter.brand()).append("、").append(matter.model()).append("、平米价格:").append(matter.price()).append(" 元。\n");}return detail.toString();}}
package com.lm.design.test;import com.lm.design.DecorationPackageController;
import org.junit.Test;import java.math.BigDecimal;public class ApiTest {@Testpublic void test_DecorationPackageController(){DecorationPackageController decoration = new DecorationPackageController();// 豪华欧式System.out.println(decoration.getMatterList(new BigDecimal("132.52"),1));// 轻奢田园System.out.println(decoration.getMatterList(new BigDecimal("98.25"),2));// 现代简约System.out.println(decoration.getMatterList(new BigDecimal("85.43"),3));}}

建造者模式重构代码
建造者模式主要解决的问题是在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的过程构成;由于需求的变化,这个复杂对象的各个部分经常面临着重大的变化,但是将它们组合在一起的过程却相对稳定。

我们会把构建的过程交给创建者类,而创建者通过使用我们的构建工具包,去构建出不同的装修套餐。

在这里插入图片描述
工程中有三个核心类和一个测试类,核心类是建造者模式的具体实现。与ifelse实现方式相比,多出来了两个额外的类。具体功能如下;

Builder,建造者类具体的各种组装由此类实现。
DecorationPackageMenu,是IMenu接口的实现类,主要是承载建造过程中的填充器。相当于这是一套承载物料和创建者中间衔接的内容。
定义装修包接口

package com.lm.design;public interface IMenu {/*** 吊顶*/IMenu appendCeiling(Matter matter);/*** 涂料*/IMenu appendCoat(Matter matter);/*** 地板*/IMenu appendFloor(Matter matter);/*** 地砖*/IMenu appendTile(Matter matter);/*** 明细*/String getDetail();}

接口类中定义了填充各项物料的方法;吊顶、涂料、地板、地砖,以及最终提供获取全部明细的方法。

装修包实现

package com.lm.design;import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;/*** 装修包*/
public class DecorationPackageMenu implements IMenu {private List<Matter> list = new ArrayList<Matter>();  // 装修清单private BigDecimal price = BigDecimal.ZERO;      // 装修价格private BigDecimal area;  // 面积private String grade;     // 装修等级;豪华欧式、轻奢田园、现代简约private DecorationPackageMenu() {}public DecorationPackageMenu(Double area, String grade) {this.area = new BigDecimal(area);this.grade = grade;}public IMenu appendCeiling(Matter matter) {list.add(matter);price = price.add(area.multiply(new BigDecimal("0.2")).multiply(matter.price()));return this;}public IMenu appendCoat(Matter matter) {list.add(matter);price = price.add(area.multiply(new BigDecimal("1.4")).multiply(matter.price()));return this;}public IMenu appendFloor(Matter matter) {list.add(matter);price = price.add(area.multiply(matter.price()));return this;}public IMenu appendTile(Matter matter) {list.add(matter);price = price.add(area.multiply(matter.price()));return this;}public String getDetail() {StringBuilder detail = new StringBuilder("\r\n-------------------------------------------------------\r\n" +"装修清单" + "\r\n" +"套餐等级:" + grade + "\r\n" +"套餐价格:" + price.setScale(2, BigDecimal.ROUND_HALF_UP) + " 元\r\n" +"房屋面积:" + area.doubleValue() + " 平米\r\n" +"材料清单:\r\n");for (Matter matter: list) {detail.append(matter.scene()).append(":").append(matter.brand()).append("、").append(matter.model()).append("、平米价格:").append(matter.price()).append(" 元。\n");}return detail.toString();}}

装修包的实现中每一个方法都返回了 this,也就可以非常方便的用于连续填充各项物料。

建造者方法

package com.lm.design;import com.lm.design.ceiling.LevelOneCeiling;
import com.lm.design.ceiling.LevelTwoCeiling;
import com.lm.design.coat.DuluxCoat;
import com.lm.design.coat.LiBangCoat;
import com.lm.design.floor.ShengXiangFloor;
import com.lm.design.tile.DongPengTile;
import com.lm.design.tile.MarcoPoloTile;public class Builder {public IMenu levelOne(Double area) {return new DecorationPackageMenu(area, "豪华欧式").appendCeiling(new LevelTwoCeiling())    // 吊顶,二级顶.appendCoat(new DuluxCoat())             // 涂料,多乐士.appendFloor(new ShengXiangFloor());     // 地板,圣象}public IMenu levelTwo(Double area){return new DecorationPackageMenu(area, "轻奢田园").appendCeiling(new LevelTwoCeiling())   // 吊顶,二级顶.appendCoat(new LiBangCoat())           // 涂料,立邦.appendTile(new MarcoPoloTile());       // 地砖,马可波罗}public IMenu levelThree(Double area){return new DecorationPackageMenu(area, "现代简约").appendCeiling(new LevelOneCeiling())   // 吊顶,二级顶.appendCoat(new LiBangCoat())           // 涂料,立邦.appendTile(new DongPengTile());        // 地砖,东鹏}}

建造者的使用中就已经非常容易了,统一的建造方式,通过不同物料填充出不同的装修风格;豪华欧式、轻奢田园、现代简约,如果将来业务扩展也可以将这部分内容配置到数据库自动生成。但整体的思想还可以使用创建者模式进行搭建。

测试验证

package com.lm.design.test;import com.lm.design.Builder;
import org.junit.Test;public class ApiTest {@Testpublic void test_Builder(){Builder builder = new Builder();// 豪华欧式System.out.println(builder.levelOne(132.52D).getDetail());// 轻奢田园System.out.println(builder.levelTwo(98.25D).getDetail());// 现代简约System.out.println(builder.levelThree(85.43D).getDetail());}}

总结
1:通过上面对建造者模式的使用,已经可以摸索出一点心得。那就是什么时候会选择这样的设计模式,当:一些基本物料不会变,而其组合经常变化的时候,就可以选择这样的设计模式来构建代码。
2:此设计模式满足了单一职责原则以及可复用的技术、建造者独立、易扩展、便于控制细节风险。但同时当出现特别多的物料以及很多的组合后,类的不断扩展也会造成难以维护的问题。但这种设计3:结构模型可以把重复的内容抽象到数据库中,按照需要配置。这样就可以减少代码中大量的重复。
好了 设计模式之建造者模式(各项装修物料组合套餐选配场景) 学习结束了 友友们 点点关注不迷路 老铁们!!!!!

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

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

相关文章

ffmpeg视频滤镜:组合两个视频为立体视频- framepack

视频描述 framepack 官方网址 > FFmpeg Filters Documentation 这个滤镜会将两个视频进行组合&#xff0c;有个前提是这两个视频的帧率、分别率必须一样。比如输入的是两个852x480 视频&#xff0c;输出可能是1704*480&#xff08;左右拼接&#xff09;、852*960&#xf…

【K8S问题系列 | 8】K8S集群资源突然爆满导致 Pod 状态变为 Pending 详细解决方案

在 Kubernetes 集群中&#xff0c;当 CPU 突然爆满时&#xff0c;Pod 可能无法获得所需的资源&#xff0c;从而导致其状态变为 Pending。以下是更详细的解决方案描述&#xff0c;有效应对这一问题。 解决方案 1: 扩展集群资源 描述 当集群资源不足以支撑当前的工作负载时&…

第18篇 :深入剖析systemverilog中 randomize 失败案例启示录(一)

经过前面章节的理论学习&#xff0c;我们对systemverilog中的随机约束&#xff0c;有一定的了解&#xff0c;那么&#xff0c;今天开始&#xff0c;着重讲述一些工作中遇到的困惑。主要通过一些例子&#xff0c;层层递进&#xff0c;举一反三&#xff0c;源于实践&#xff0c;剖…

mac端mumu模拟器adb识别不了问题

1.在终端中输入&#xff1a;system_profiler SPUSBDataType,把0x05e3 (Genesys Logic, Inc.)复制 2. 1.cd ~/.android/ 2.open . 3.找到.android/adb_usb.ini文件 将以上格式的Wendor ID放入该文件 3.依次执行 * adb devices* adb kill-server* adb start-server* adb disco…

Ubuntu版本、ROS版本与Python 版本之间的关系

引言 在机器人开发中&#xff0c;ROS&#xff08;机器人操作系统&#xff09;广泛应用于科研和工业领域&#xff0c;支持多个Ubuntu和Python版本。然而&#xff0c;随着不同Ubuntu LTS版本的发布以及Python逐渐从2.x向3.x过渡&#xff0c;ROS的版本选择和兼容性要求也在不断变化…

Linux - 信号

文章目录 一、信号的定义二、查看信号三、产生信号1、指令2、系统调用3、由软件条件产生信号4、异常5、键盘输入 四、保存信号1、补充&#xff1a;信号其他相关概念2、信号保存在哪&#xff0c;怎么保存&#xff1f;3、信号集操作函数 五、捕获信号1、概念2、捕获信号的时机3、…

PMP–知识卡片--项目干系人

项目干系人主要分为两类&#xff1a;参与项目的人和受项目影响的人。按照由近及远&#xff0c;从项目经理、项目团队等逐渐扩充至供应商、客户、监管机构等。 项目往往死在被忽略的干系人手上&#xff0c;作为项目经理&#xff0c;要尽可能地识别出来所有可能影响项目以及受项目…

MATLAB - ROS 2 分析器

系列文章目录 前言 本主题介绍如何连接 ROS 2 网络&#xff0c;分析网络图中所有元素的基本信息&#xff08;如节点名称和节点之间的信息&#xff09;&#xff0c;以及可视化与 ROS 2 节点相关的参数&#xff08;如主题、服务和操作&#xff09;之间的交互。 一、连接并查看 RO…

分组校验在Spring中的应用详解

目录 前言1. 什么是分组校验2. 分组校验的基本原理3. 分组校验的实现步骤3.1 定义分组接口3.2 在校验项中指定分组3.3 校验时指定要校验的分组3.4 默认分组和分组的继承 4. 分组校验的优势和适用场景4.1 优势4.2 适用场景 5. 常见问题与解决方案5.1 校验未生效5.2 无法识别默认…

SDL打开YUV视频

文章目录 问题1&#xff1a;如何控制帧率&#xff1f;问题2&#xff1a;如何触发退出事件&#xff1f;问题3&#xff1a;如何实时调整视频窗口的大小问题4&#xff1a;YUV如何一次读取一帧的数据&#xff1f; 问题1&#xff1a;如何控制帧率&#xff1f; 单独用一个子线程给主线…

[MySQL]索引

索引介绍 索引是帮助数据库高效获取数据的数据结构。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用数据&#xff0c; 这样就可以在这些数据结构上实现高级查找算法&#xff0c;这种数据结构就是索引。 假设我们有…

window 利用Putty免密登录远程服务器

1 在本地电脑用putty-gen生成密钥 参考1 参考2 2 服务器端操作 将公钥上传至Linux服务器。 复制上述公钥到服务器端的authorized_keys文件 mkdir ~/.ssh vi ~/.ssh/authorized_keys在vi编辑器中&#xff0c;按下ShiftInsert键或者右键选择粘贴&#xff0c;即可将剪贴板中的文…

【大数据技术基础 | 实验八】HBase实验:新建HBase表

文章目录 一、实验目的二、实验要求三、实验原理四、实验环境五、实验内容和步骤&#xff08;一&#xff09;启动HBase集群&#xff08;二&#xff09;编写项目java代码&#xff08;三&#xff09;将代码导出jar包 六、实验结果七、实验心得 一、实验目的 掌握HBase数据模型(逻…

密钥管理服务 (KMS) 故障排除指南

企业客户将密钥管理服务 (KMS) 设置为部署流程的一部分&#xff0c;因为通过该服务&#xff0c;他们可以使用简单、直接的过程在其环境中激活 Windows。 通常&#xff0c;一旦设置了 KMS 主机&#xff0c;KMS 客户端就会自动连接到主机并自行激活。 然而&#xff0c;有时该流程…

CSS的配色

目录 1 十六进制2 CSS中的十六进制2.1 十六进制颜色的基本结构2.2 十六进制颜色的范围2.3 简写形式2.4 透明度 3 CSS的命名颜色4 配色4.1 色轮4.2 互补色4.3 类似色4.4 配色工具 日常在开发小程序中&#xff0c;客户总是希望你的配色是美的&#xff0c;但是美如何定义&#xff…

基于 RNN 的语言模型

基于 RNN 的语言模型 循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;是一类网络连接中包含环路的 神经网络的总称。 给定一个序列&#xff0c;RNN 的环路用于将历史状态叠加到当前状态上。沿着时间维度&#xff0c;历史状态被循环累积&#xff0c;并作为…

【软考网工笔记】网络基础理论——物理层

文章目录 贝尔系统 T1 载波光纤 - SFP接口差分&&曼彻斯特编码网桥MAC-in-MACQ-in-QIPv6的链路本地地址CRC校验与计算E1载波编码效率对称xDSL坚持算法-CSMAUDP头部字段万兆以太网标准 IEEE 802.3ae海明码-纠错码ARP帧中的目标MAC地址快速以太区网物理层标准 100BASE-TXM…

现代Web开发:TypeScript 深入解析与最佳实践

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 现代Web开发&#xff1a;TypeScript 深入解析与最佳实践 现代Web开发&#xff1a;TypeScript 深入解析与最佳实践 现代Web开发&a…

HCIP MPLS基础

一、 实验拓扑 二、 实验需求及解法 本实验模拟BGP路由黑洞环境&#xff0c;使用MPLS LDP解决路由黑洞。 完成以下需求&#xff1a; 1.设备IP地址配置&#xff0c;请测试直连。 sysname R1 interface GigabitEthernet0/0/0ip address 12.1.1.1 255.255.255.0interface Loop…

Kubernetes架构及核心组件

一、基本架构 Kubernetes集群可以被看作是一个工厂,而各个组件则是这个工厂里的不同部门: Kubernetes API服务器:就像是这个工厂的总经理,负责接收所有的请求并将它们分配给相应的部门进行处理。 etcd:就像是这个工厂的记事本,负责记录所有的配置信息和状态信息,以便其…