前言:
乱码七糟,我时常怀疑这个成语是来形容程序猿的!
无论承接什么样的需求,是不是身边总有那么几个人代码写的烂,但是却时常有测试小姐姐过来聊天(求改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:结构模型可以把重复的内容抽象到数据库中,按照需要配置。这样就可以减少代码中大量的重复。
好了 设计模式之建造者模式(各项装修物料组合套餐选配场景) 学习结束了 友友们 点点关注不迷路 老铁们!!!!!