设计模式学习笔记-4 创建者模式-建造者模式
建造者模式就是通过多个简单对象通过一步步的组装构建出一个复杂对象的过程。
场景模拟
模拟装修公司想推出一些套餐装修服务,按照不同的价格设定品牌选择组合,模拟装修中所需要的物料Ceiling,Coat,Floor,Tile
物料接口
import java.math.BigDecimal;
public interface Matter {
/**
* 场景
* 地板/地砖/涂料/吊顶
*
* @return String
*/
String scene();
/**
* 品牌
*
* @return String
*/
String brand();
/**
* 型号
*
* @return String
*/
String model();
/**
* 价格
*
* @return BigDecimal
*/
BigDecimal price();
/**
* 描述
*
* @return String
*/
String desc();
}
- 此接口提供了基本的信息,保证所有的装修材料都按照统一标准进行获取。
吊顶类
一级顶
import com.yaroo.head_first_demo.design_pattern.demo4_01.Matter;
import java.math.BigDecimal;
public class LevelOneCeiling implements Matter {
@Override
public String scene() {
return "吊顶";
}
@Override
public String brand() {
return "装修公司自带";
}
@Override
public String model() {
return "一级顶";
}
@Override
public BigDecimal price() {
return new BigDecimal(260);
}
@Override
public String desc() {
return "造型只做低⼀级,只有⼀个层次的吊顶,⼀般离顶120-150mm";
}
}
二级顶
import com.yaroo.head_first_demo.design_pattern.demo4_01.Matter;
import java.math.BigDecimal;
public class LevelTwoCeiling implements Matter {
@Override
public String scene() {
return "吊顶";
}
@Override
public String brand() {
return "装修公司自带";
}
@Override
public String model() {
return "二级顶";
}
@Override
public BigDecimal price() {
return new BigDecimal(850);
}
@Override
public String desc() {
return "两个层次的吊顶,⼆级吊顶⾼度⼀般就往下吊20cm,要是层⾼很⾼,也可增加每级的厚度";
}
}
涂料
多乐士
import com.yaroo.head_first_demo.design_pattern.demo4_01.Matter;
import java.math.BigDecimal;
public class DuluxCoat implements Matter {
@Override
public String scene() {
return "涂料";
}
@Override
public String brand() {
return "多乐士(Dulux)";
}
@Override
public String model() {
return "第二代";
}
@Override
public BigDecimal price() {
return new BigDecimal(719);
}
@Override
public String desc() {
return "多乐⼠是阿克苏诺⻉尔旗下的著名建筑装饰油漆品牌,产品畅销于全球100个国家,每年全球有5000万户家庭使⽤多乐⼠油漆。";
}
}
立邦
import com.yaroo.head_first_demo.design_pattern.demo4_01.Matter;
import java.math.BigDecimal;
public class LiBangCoat implements Matter {
@Override
public String scene() {
return "涂料";
}
@Override
public String brand() {
return "立邦";
}
@Override
public String model() {
return "默认级别";
}
@Override
public BigDecimal price() {
return new BigDecimal(650);
}
@Override
public String desc() {
return "⽴邦始终以开发绿⾊产品、注᯿⾼科技、⾼品质为⽬标,以技术⼒量不断推进科研和开发,满⾜消费者需求。";
}
}
地板
德尔
import com.yaroo.head_first_demo.design_pattern.demo4_01.Matter;
import java.math.BigDecimal;
public class DerFloor implements Matter {
@Override
public String scene() {
return "地板";
}
@Override
public String brand() {
return "德尔(Der)";
}
@Override
public String model() {
return "A+";
}
@Override
public BigDecimal price() {
return new BigDecimal(119);
}
@Override
public String desc() {
return "DER德尔集团是全球领先的专业⽊地板制造商,北京2008年奥运会家装和公装地板供应商";
}
}
圣象
import com.yaroo.head_first_demo.design_pattern.demo4_01.Matter;
import java.math.BigDecimal;
public class ShengXiangFloor implements Matter {
@Override
public String scene() {
return "地板";
}
@Override
public String brand() {
return "圣象";
}
@Override
public String model() {
return "一级";
}
@Override
public BigDecimal price() {
return new BigDecimal(318);
}
@Override
public String desc() {
return "圣象地板是中国地板⾏业著名品牌。圣象地板拥有中国驰名商标、中国名牌、国家免检、中国环境标志认证等多项荣誉。";
}
}
地板
东鹏
import com.yaroo.head_first_demo.design_pattern.demo4_01.Matter;
import java.math.BigDecimal;
public class DongPengTile implements Matter {
@Override
public String scene() {
return "地板";
}
@Override
public String brand() {
return "东鹏瓷砖";
}
@Override
public String model() {
return "10001";
}
@Override
public BigDecimal price() {
return new BigDecimal(102);
}
@Override
public String desc() {
return "东鹏瓷砖以品质铸就品牌,科技推动品牌,⼝碑传播品牌为宗旨,2014年品牌价值132.35亿元,位列建陶⾏业榜⾸。";
}
}
马可波罗
import com.yaroo.head_first_demo.design_pattern.demo4_01.Matter;
import java.math.BigDecimal;
public class MarcoPoloTile implements Matter {
@Override
public String scene() {
return "地砖";
}
@Override
public String brand() {
return "马可波罗(MARCO POLO)";
}
@Override
public String model() {
return "缺省";
}
@Override
public BigDecimal price() {
return new BigDecimal(140);
}
@Override
public String desc() {
return "⻢可波罗”品牌诞⽣于1996年,作为国内最早品牌化的建陶品牌,以“瓷”占领市场,享有“仿古砖⾄尊”的美誉。";
}
}
普通实现
使用if else
实现
import com.yaroo.head_first_demo.design_pattern.demo4_01.ceiling.LevelOneCeiling;
import com.yaroo.head_first_demo.design_pattern.demo4_01.ceiling.LevelTwoCeiling;
import com.yaroo.head_first_demo.design_pattern.demo4_01.coat.DuluxCoat;
import com.yaroo.head_first_demo.design_pattern.demo4_01.coat.LiBangCoat;
import com.yaroo.head_first_demo.design_pattern.demo4_01.floor.ShengXiangFloor;
import com.yaroo.head_first_demo.design_pattern.demo4_01.tile.DongPengTile;
import com.yaroo.head_first_demo.design_pattern.demo4_01.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<>();
// 装修价格
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();
}
}
- 首先需要解决入参问题,装修面积与装修等级需要根据不同的装修等级选择不同的材料
- 其次没有if分支内,都包含不同的材料,最终才生成装修清单和装修成本
- 最后提供获取装修详细信息的方法,返回给调用方
单元测试
测试方法
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
class DecorationPackageControllerTest {
@Test
void getMatterList() {
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 元。
使用构造者模式重构代码
定义装修包接口
import com.yaroo.head_first_demo.design_pattern.demo4_01.Matter;
public interface IMenu {
/**
* 吊顶
* @param matter
* @return
*/
IMenu appendCeiling(Matter matter);
/**
* 涂料
* @param matter
* @return
*/
IMenu appendCoat(Matter matter);
/**
* 地板
* @param matter
* @return
*/
IMenu appendFloor(Matter matter);
/**
* 地砖
* @param matter
* @return
*/
IMenu appendTile(Matter matter);
/**
* 明细
* @return
*/
String getDetail();
}
- 接口类中定义了各种填充物料的方法以及最终提供获取全部明细的方法。
装修包实现
import com.yaroo.head_first_demo.design_pattern.demo4_01.Matter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* IMenu的实现类
* 主要是承载建造过程中的填充器
*/
public class DecorationPackageMenu implements IMenu{
// 装修清单
private List<Matter> list = new ArrayList<>();
// 装修价格
private BigDecimal price = BigDecimal.ZERO;
// 面积
private BigDecimal area;
// 装修等级
private String grade;
public DecorationPackageMenu(BigDecimal area, String grade) {
this.area = area;
this.grade = grade;
}
@Override
public IMenu appendCeiling(Matter matter) {
list.add(matter);
price = price.add(area.multiply(new BigDecimal("0.2")).multiply(matter.price()));
return this;
}
@Override
public IMenu appendCoat(Matter matter) {
list.add(matter);
price = price.add(area.multiply(new
BigDecimal("1.4")).multiply(matter.price()));
return this;
}
@Override
public IMenu appendFloor(Matter matter) {
list.add(matter);
price = price.add(area.multiply(matter.price()));
return this;
}
@Override
public IMenu appendTile(Matter matter) {
list.add(matter);
price = price.add(area.multiply(matter.price()));
return this;
}
@Override
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,也就可以非常方便的用于连续填充各项物料
建造者方法
import com.yaroo.head_first_demo.design_pattern.demo4_01.ceiling.LevelOneCeiling;
import com.yaroo.head_first_demo.design_pattern.demo4_01.ceiling.LevelTwoCeiling;
import com.yaroo.head_first_demo.design_pattern.demo4_01.coat.DuluxCoat;
import com.yaroo.head_first_demo.design_pattern.demo4_01.coat.LiBangCoat;
import com.yaroo.head_first_demo.design_pattern.demo4_01.floor.ShengXiangFloor;
import com.yaroo.head_first_demo.design_pattern.demo4_01.tile.DongPengTile;
import com.yaroo.head_first_demo.design_pattern.demo4_01.tile.MarcoPoloTile;
import java.math.BigDecimal;
/**
* 建造者类具体的各种组装由该类实现
*/
public class Builder {
public IMenu levelOne(BigDecimal area) {
return new DecorationPackageMenu(area, "豪华欧式")
.appendCeiling(new LevelTwoCeiling()) // 吊顶,⼆级顶
.appendCoat(new DuluxCoat()) // 涂料,多乐⼠
.appendFloor(new ShengXiangFloor()); // 地板,圣象
}
public IMenu levelTwo(BigDecimal area) {
return new DecorationPackageMenu(area, "轻奢⽥园")
.appendCeiling(new LevelTwoCeiling()) // 吊顶,⼆级顶
.appendCoat(new LiBangCoat()) // 涂料,⽴邦
.appendTile(new MarcoPoloTile()); // 地砖,⻢可波罗
}
public IMenu levelThree(BigDecimal area) {
return new DecorationPackageMenu(area, "现代简约")
.appendCeiling(new LevelOneCeiling()) // 吊顶,⼆级顶
.appendCoat(new LiBangCoat()) // 涂料,⽴邦
.appendTile(new DongPengTile()); // 地砖,东鹏
}
}
单元测试
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
class BuilderTest {
@Test
void test_builder() {
Builder builder = new Builder();
// 豪华欧式
System.out.println(builder.levelOne(new BigDecimal("132.52")).getDetail());
// 轻奢⽥园
System.out.println(builder.levelTwo(new BigDecimal("98.25")).getDetail());
// 现代简约
System.out.println(builder.levelThree(new BigDecimal("85.43")).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 元。