设计模式 - 创建型模式_建造者模式
创始人
2024-05-19 11:08:02
0

文章目录

  • 创建型模式
  • 概述
  • Case
  • 模拟工程
  • Bad Impl
  • Better Impl (建造者模式重构代码)
  • 小结

在这里插入图片描述


创建型模式

创建型模式提供创建对象的机制, 能够提升已有代码的灵活性和可复⽤性。

类型实现要点
工厂方法定义⼀个创建对象的接⼝,让其⼦类⾃⼰决定实例化哪⼀个⼯⼚类,⼯⼚模式使其创建过程延迟到⼦类进⾏。
抽象工厂提供⼀个创建⼀系列相关或相互依赖对象的接⼝,⽽⽆需指定它们具体的类。
建造者将⼀个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示
原型⽤原型实例指定创建对象的种类,并且通过拷⻉这些原型创建新的对象。
单例保证⼀个类仅有⼀个实例,并提供⼀个访问它的全局访问点。

概述

在这里插入图片描述

建造者模式所完成的内容就是通过将多个简单对象通过⼀步步的组装构建出⼀个复杂对象的过程。

举个例子玩王者荣耀的时的初始化界⾯;有三条路、有树⽊、有野怪、有守卫塔等等,甚⾄依赖于你的⽹络情况会控制清晰度。⽽当你换⼀个场景进⾏其他不同模式的选择时,同样会建设道路、树⽊、野怪等等,但是他们的摆放和⼤⼩都有不同。这⾥就可以⽤到建造者模式来初始化游戏元素。

⽽这样的根据相同的物料 ,不同的组装所产⽣出的具体的内容,就是建造者模式的最终意图,也就是将⼀个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。


Case

在这里插入图片描述

模拟装修公司对于设计出⼀些套餐装修服务的场景。

套餐服务:欧式豪华、轻奢⽥园、现代简约等等,⽽这些套餐的后⾯是不同的商品的组合。例如: ⼀级&⼆级吊顶、多乐⼠涂料、圣象地板、⻢可波罗地砖等等,按照不同的套餐的价格选取不同的品牌组合,最终再按照装修⾯积给出⼀个整体的报价。

这⾥我们就模拟装修公司想推出⼀些套餐装修服务,按照不同的价格设定品牌选择组合,以达到使⽤建造者模式的过程。


模拟工程

在这里插入图片描述
提供了装修中所需要的物料: ceilling(吊顶) 、 coat(涂料) 、 floor(地板) 、tile(地砖) ,这四项内容。

【 物料接⼝ 】

public interface Matter {/*** 场景;地板、地砖、涂料、吊顶*/String scene();/*** 品牌*/String brand();/*** 型号*/String model();/*** 平米报价*/BigDecimal price();/*** 描述*/String desc();}

物料接⼝提供了基本的信息,以保证所有的装修材料都可以按照统⼀标准进⾏获取

具体的材料,我们以一级顶为例

在这里插入图片描述

/*** 吊顶* 品牌;装修公司自带* 型号:一级顶*/
public class LevelOneCeiling implements Matter {public String scene() {return "吊顶";}public String brand() {return "装修公司自带";}public String model() {return "一级顶";}public BigDecimal price() {return new BigDecimal(260);}public String desc() {return "造型只做低一级,只有一个层次的吊顶,一般离顶120-150mm";}}

其他材料同样的实现了Matter接口 。
在这里插入图片描述

以上就是装修配置单 ,接下我们去使⽤不同的物料组合出不同的套餐服务。


Bad Impl

讲道理没有ifelse解决不了的逻辑,不⾏就在加⼀⾏!

我们先使⽤这样很直⽩的⽅式去把功能实现出来,在通过设计模式去优化完善。

⼀个类⼏千⾏的代码你是否⻅过,那今天⻅识⼀下有这样潜质的类!


public class DecorationPackageController {public String getMatterList(BigDecimal area, Integer level) {List list = new ArrayList(); // 装修清单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();}}
  • ⾸先这段代码所要解决的问题就是接收⼊参: 装修⾯积(area)、装修等级(level),根据不同类型的装修等级选择不同的材料。
  • 其次在实现过程中可以看到每⼀段 if 块⾥,都包含着不通的材料(吊顶,⼆级顶、涂料,⽴邦、地砖,⻢可波罗),最终⽣成装修清单和装修成本。
  • 最后提供获取装修详细信息的⽅法,返回给调⽤⽅,⽤于知道装修清单。

【单元测试】

接下来我们通过junit单元测试的⽅式验证接⼝服务,强调⽇常编写好单测可以更好的提⾼系统的健壮度。

  @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));}

-------------------------------------------------------
装修清单
套餐等级:1
套餐价格:198064.39 元
房屋面积:132.52 平米
材料清单:
吊顶:装修公司自带、二级顶、平米价格:850 元。
涂料:多乐士(Dulux)、第二代、平米价格:719 元。
地板:圣象、一级、平米价格:318 元。-------------------------------------------------------
装修清单
套餐等级:2
套餐价格:119865.00 元
房屋面积:98.25 平米
材料清单:
吊顶:装修公司自带、二级顶、平米价格:850 元。
涂料:立邦、默认级别、平米价格:650 元。
地砖:马可波罗(MARCO POLO)、缺省、平米价格:140 元。-------------------------------------------------------
装修清单
套餐等级:3
套餐价格:90897.52 元
房屋面积:85.43 平米
材料清单:
吊顶:装修公司自带、一级顶、平米价格:260 元。
涂料:立邦、默认级别、平米价格:650 元。
地砖:东鹏瓷砖、10001、平米价格:102 元。

以上这段使⽤ ifelse ⽅式实现的代码,⽬前已经满⾜的我们的也许功能。

但随着业务的快速发展要求,会提供很多的套餐针对不同的户型。那么这段实现代码将迅速扩增到⼏千⾏,甚⾄在修修改改中,已经像膏药⼀样难以维护。

在这里插入图片描述


Better Impl (建造者模式重构代码)

接下来使⽤建造者模式来进⾏代码优化,也算是⼀次很⼩的重构

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

这⾥我们会把构建的过程交给 创建者 类,⽽创建者通过使⽤我们的 构建⼯具包 ,去构建出不同的 装修套餐。

【工程结构】
在这里插入图片描述

建造者模式代码类关系

在这里插入图片描述

建造者模型结构

在这里插入图片描述

核⼼类是建造者模式的具体实现。与 ifelse 实现⽅式相⽐,多出来了两个额外的类。具体功能如下:

  • Builder ,建造者类具体的各种组装由此类实现
  • DecorationPackageMenu ,是 IMenu 接⼝的实现类,主要是承载建造过程中的填充器。这是⼀套承载物料和创建者中间衔接的内容。

【装修包接口】

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

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


【装修包实现】

/*** 装修包*/
public class DecorationPackageMenu implements IMenu {private List list = new ArrayList();  // 装修清单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 ,也就可以⾮常⽅便的⽤于连续填充各项物料。
  • 同时在填充时也会根据物料计算平⽶数下的报价,吊顶和涂料按照平⽶数适量乘以常数计算。
  • 最后同样提供了统⼀的获取装修清单的明细⽅法

【 建造者⽅法】


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());        // 地砖,东鹏}}

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


【单元测试】

   @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());}

-------------------------------------------------------
装修清单
套餐等级:豪华欧式
套餐价格:198064.39 元
房屋面积:132.52 平米
材料清单:
吊顶:装修公司自带、二级顶、平米价格:850 元。
涂料:多乐士(Dulux)、第二代、平米价格:719 元。
地板:圣象、一级、平米价格:318 元。-------------------------------------------------------
装修清单
套餐等级:轻奢田园
套餐价格:119865.00 元
房屋面积:98.25 平米
材料清单:
吊顶:装修公司自带、二级顶、平米价格:850 元。
涂料:立邦、默认级别、平米价格:650 元。
地砖:马可波罗(MARCO POLO)、缺省、平米价格:140 元。-------------------------------------------------------
装修清单
套餐等级:现代简约
套餐价格:90897.52 元
房屋面积:85.43 平米
材料清单:
吊顶:装修公司自带、一级顶、平米价格:260 元。
涂料:立邦、默认级别、平米价格:650 元。
地砖:东鹏瓷砖、10001、平米价格:102 元。

测试结果是⼀样的,调⽤⽅式也基本类似。但是⽬前的代码结构却可以很⽅便的很有调理的进⾏扩展业务开发。⽽不是以往⼀样把所有代码都写到 ifelse ⾥⾯。


小结

当⼀些基本物料不会变,⽽其组合经常变化的时候 ,就可以选择这样的设计模式来构建代码。

此设计模式满⾜了单⼀职责原则以及可复⽤的技术、建造者独⽴、易扩展、便于控制细节⻛险。

同时当出现特别多的物料以及很多的组合后,类的不断扩展也会造成难以维护的问题。但这种设计结构模型可以把重复的内容抽象到数据库中,按照需要配置。这样就可以减少代码中⼤量的重复。

在这里插入图片描述

相关内容

热门资讯

我在变的作文400字 我在变的作文400字  作文【第1篇】  我上初中快一个月了,我发现成在变。  在学校的每一个人,都...
伤仲永的作文750字 伤仲永的作文750字  最近读了王安石的名篇《伤仲永》。这篇文章讲了一个故事:江西金溪县有个叫方仲永...
邻里和睦的作文 关于邻里和睦的作文范文  在日常学习、工作和生活中,许多人都写过作文吧,借助作文人们可以反映客观事物...
跳皮筋作文400字 跳皮筋作文400字  下午放学,我和思思走到了我家开的店门口,正要告别,思思突然说:“我们跳一下皮筋...
《斯梦索尼克传奇》简介 -作... 《斯梦索尼克传奇》简介 -作文作者:星洛 (安徽省安庆市人民路小学 劳毅凡) 《斯梦...
风雨中的美丽作文 风雨中的美丽作文(精选10篇)  在日常生活或是工作学习中,大家或多或少都会接触过作文吧,作文是人们...
我的新发现作文 我的新发现作文精选10篇  在平平淡淡的学习、工作、生活中,许多人都有过写作文的经历,对作文都不陌生...
风雨的磨炼作文 风雨的磨炼作文  人们常说现在的我们是祖国的花朵。但花儿也是各种各样的:有卑微的;有在恶劣的自然环境...
梦影450字作文 梦影450字作文  梦影 在那一刻,我仿佛看见整个世界崩溃在我的面前。废墟中那一片片的瓦砖都刻有鲜活...
星际旅途作文600字 星际旅途作文600字  在学习、工作乃至生活中,大家都尝试过写作文吧,作文是从内部言语向外部言语的过...
幸福优秀作文400字 幸福优秀作文400字(精选43篇)  无论在学习、工作或是生活中,大家都不可避免地会接触到作文吧,借...
老师作文400字 老师作文400字(通用30篇)  在学习、工作或生活中,大家都尝试过写作文吧,作文是人们把记忆中所存...
采蘑菇作文 采蘑菇作文10篇  在日常学习、工作和生活中,大家都写过作文,肯定对各类作文都很熟悉吧,作文是人们把...
谁是最可爱的人作文 关于谁是最可爱的人作文(精选16篇)  无论在学习、工作或是生活中,大家都写过作文,肯定对各类作文都...
中国文化的作文 中国文化的作文(精选23篇)  在日常学习、工作或生活中,大家都接触过作文吧,通过作文可以把我们那些...
摔倒作文300字 摔倒作文300字(通用25篇)  在日常学习、工作抑或是生活中,大家总免不了要接触或使用作文吧,作文...
东湖的夜色作文 东湖的夜色作文  春姑娘悄悄的来到了人间,新的一年也即将到来。  晚风习习,夜幕降临。月朗星稀的夜晚...
粘土制作方法作文推荐45篇 粘土制作方法作文 第一篇同学们,你们从小到大一定玩过很多次彩泥吧?没错,我也一样。今天,我又玩了一回...
指南针作文 指南针作文(精选60篇)  在我们平凡的日常里,大家都尝试过写作文吧,通过作文可以把我们那些零零散散...
心理素质的作文 关于心理素质的作文(通用49篇)  无论是在学校还是在社会中,大家总少不了接触作文吧,作文是从内部言...