一文读懂建造者模式,再也不怕面试官问我了
一、定义
将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。
二、使用范围
1.创建一个复杂的对象,他有多个不同的模块组成,其中有些模块不会改变,但是其他模块可能经常发生改变,我们不得已需要把不变的模块与常变的模块分开实现时。
2.当构造过程必须允许被构造的对象有不同表示时。
三、功能实现角色
1.builder:为创建一个产品对象的各个部件指定抽象接口。
2.ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并 提供一个检索产品的接口。
3.Director:构造一个使用Builder接口的对象。
4.Product:表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
四、实践
1.情景假设
我们在计费的过程中有一个计费模式获取类,他的功能是获取当前这个用户所需要的计费模式,但是计费有很多种,比如SMS计费(短信计费)、Cash计费(银行卡计费),其中SMS计费又包括中国移动、中国联通、印尼Tsel、印尼isat计费,Cash包括招商银行、农行、印尼Visa等,且不同支付方式给予不同的计费点和订单开头。在国外用户和国内用户时,要提供不同的计费集。
2.当前计费信息接口
[code]public interface FeeInterf { public String orderNo();//当前交易编号 public FeeTypeInterf feeType();//当前交易类型 public float price();//当前交易金额 }
3.当前计费类型接口
[code]public interface FeeTypeInterf { public String feeType(); }
4.当前计费类型的实现类
SMSFeeType
[code]import cn.yzstu.buldermodule.interf.FeeTypeInterf; /** * 类描述 * * @author: 12405 * @date: 2020/3/25-22:28 */ public class SMSFeeType implements FeeTypeInterf { @Override public String feeType() { return "SMS"; } }
CashFeeType
[code]import cn.yzstu.buldermodule.interf.FeeTypeInterf; /** * 类描述 * * @author: 12405 * @date: 2020/3/25-22:29 */ public class CashFeeType implements FeeTypeInterf { @Override public String feeType() { return "Cash"; } }
5.不同类型计费的实现类
SMS
[code]import cn.yzstu.buldermodule.impl.feetype.SMSFeeType; import cn.yzstu.buldermodule.interf.FeeInterf; import cn.yzstu.buldermodule.interf.FeeTypeInterf; /** * 类描述 * * @author: 12405 * @date: 2020/3/25-22:37 */ public abstract class SMSFee implements FeeInterf { @Override public FeeTypeInterf feeType() { return new SMSFeeType(); } }
Cash
[code]import cn.yzstu.buldermodule.impl.feetype.CashFeeType; import cn.yzstu.buldermodule.interf.FeeInterf; import cn.yzstu.buldermodule.interf.FeeTypeInterf; /** * 类描述 * * @author: 12405 * @date: 2020/3/25-22:44 */ public abstract class CashFee implements FeeInterf { @Override public FeeTypeInterf feeType() { return new CashFeeType(); } }
6.计费的详细实体类
中国移动
[code]import java.util.UUID; /** * 类描述 * * @author: 12405 * @date: 2020/3/25-22:49 */ public class ChinaMobileFee extends SMSFee { @Override public String orderNo() { return "MOBL"+ UUID.randomUUID(); } @Override public float price() { return 10.0f; } }
中国联通
[code]import java.util.UUID; /** * 类描述 * * @author: 12405 * @date: 2020/3/25-22:52 */ public class ChinaUnicomFee extends SMSFee{ @Override public String orderNo() { return "UNC"+ UUID.randomUUID(); } @Override public float price() { return 20.0f; } }
印尼TSEl
[code]import java.util.UUID; /** * 类描述 * * @author: 12405 * @date: 2020/3/25-22:56 */ public class IndoTselFee extends SMSFee { @Override public String orderNo() { return "TSEL"+ UUID.randomUUID(); } @Override public float price() { return 2000.0f; } }
印尼ISAT
[code]import java.util.UUID; /** * 类描述 * * @author: 12405 * @date: 2020/3/25-22:57 */ public class IndoIsatFee extends SMSFee { @Override public String orderNo() { return "ISAT"+ UUID.randomUUID(); } @Override public float price() { return 1000.0f; } }
招商银行
[code]import java.util.UUID; /** * 类描述 * * @author: 12405 * @date: 2020/3/25-22:58 */ public class CMBFee extends CashFee { @Override public String orderNo() { return "CMB"+ UUID.randomUUID(); } @Override public float price() { return 5.0f; } }
农业银行
[code]/** * 类描述 * * @author: 12405 * @date: 2020/3/25-23:01 */ public class ABCFee extends CashFee { @Override public String orderNo() { return "ABC"+ UUID.randomUUID(); } @Override public float price() { return 2.0f; } }
Visa
[code]import java.util.UUID; /** * 类描述 * * @author: 12405 * @date: 2020/3/25-23:02 */ public class VisaFee extends CashFee { @Override public String orderNo() { return "V"+ UUID.randomUUID(); } @Override public float price() { return 10.0f; } }
7.FeeConfig类(用于构建计费相关信息)
[code]import cn.yzstu.bulidermodule.interf.FeeInterf; import java.util.ArrayList; import java.util.List; /** * 类描述 * * @author: 12405 * @date: 2020/3/25-23:09 */ public class FeeConfig { private List<FeeInterf> feeList = new ArrayList<>(); //往当前订单中加入可选的支付方式 public void addFee(FeeInterf feeInterf){ feeList.add(feeInterf); } //展示所有可选支付方式的相关信息 public void showMyFee(){ for (FeeInterf fee : feeList){ System.out.println("OrderNo:"+fee.orderNo()); System.out.println("FeeType:"+fee.feeType().feeType()); System.out.println("Money:"+fee.price()); } } }
8.FeeBuilder类(提供给国内外的不同客户计费集)
[code]import cn.yzstu.bulidermodule.impl.fee.*; /** * 类描述 * * @author: 12405 * @date: 2020/3/25-23:23 */ public class FeeBuilder { //国内用户的支付方式 public FeeConfig prepareChinaFee(){ FeeConfig feeConfig = new FeeConfig(); feeConfig.addFee(new ChinaMobileFee()); feeConfig.addFee(new ChinaUnicomFee()); feeConfig.addFee(new ABCFee()); feeConfig.addFee(new CMBFee()); return feeConfig; } //国外用户的支付方式 public FeeConfig prepareIndoFee(){ FeeConfig feeConfig = new FeeConfig(); feeConfig.addFee(new IndoIsatFee()); feeConfig.addFee(new IndoTselFee()); feeConfig.addFee(new VisaFee()); return feeConfig; } }
9.FeeDemo测试(展示国内用户获取的计费集)
[code]/** * 类描述 * * @author: 12405 * @date: 2020/3/25-23:30 */ public class FeeDemo { public static void main(String[] args) { //获取国内计费集 FeeConfig cFeeConfig = FeeBuilder.prepareChinaFee(); //获取国外计费集 FeeConfig iFeeConfig = FeeBuilder.prepareIndoFee(); //展示国内用户能够获取到的计费集 cFeeConfig.showMyFee(); } }
[code]"C:\Program Files\Java\jdk1.8.0_171\bin\java.exe" "-javaagent:E:\tools\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=54341:E:\tools\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_171\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\rt.jar;E:\Workspaces\IdeaProjects\DemoTest\out\production\DemoTest" cn.yzstu.bulidermodule.FeeDemo OrderNo:MOBL3a989c63-ce7f-4210-8193-adcab306929f FeeType:SMS Money:10.0 OrderNo:UNCd3504a9d-62a5-4fde-91a1-49e1d1df2b23 FeeType:SMS Money:20.0 OrderNo:ABC33369090-2639-4653-82fa-f76fb397fa24 FeeType:Cash Money:2.0 OrderNo:CMB845f2043-e297-49fd-b397-a061be5adf64 FeeType:Cash Money:5.0 Process finished with exit code 0
10.组件变动
上面我们已经用Builder成功获取到了我们想要的国内用户的计费方式集,其中FeeType是组件中不常改动的地方,而计费私有的属性则是我们经常改动的地方,比如我们现在想改动中国移动的计费点,直接在ChinaMobileFee中改动价格即可。
[code]import java.util.UUID; /** * 类描述 * * @author: 12405 * @date: 2020/3/25-22:49 */ public class ChinaMobileFee extends SMSFee { @Override public String orderNo() { return "MOBL"+ UUID.randomUUID(); } @Override public float price() { return 20.0f;//改动价格 } }
[code]"C:\Program Files\Java\jdk1.8.0_171\bin\java.exe" "-javaagent:E:\tools\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=54431:E:\tools\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_171\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\rt.jar;E:\Workspaces\IdeaProjects\DemoTest\out\production\DemoTest" cn.yzstu.bulidermodule.FeeDemo OrderNo:MOBLd3140a28-55a3-4cb4-8de8-ce32043a3833 FeeType:SMS Money:20.0 OrderNo:UNCb562defd-287b-4957-9a2c-e12a782a616b FeeType:SMS Money:20.0 OrderNo:ABCc6b54887-f18a-4e8a-b060-7a3fe6015a07 FeeType:Cash Money:2.0 OrderNo:CMB21663c63-9a66-4b99-9ade-d5d9659975d3 FeeType:Cash Money:5.0 Process finished with exit code 0
五、总结
该模式的主要优点如下:
- 各个具体的建造者相互独立,有利于系统的扩展。
- 客户端不必知道产品内部组成的细节,便于控制细节风险。
其缺点如下:
-
产品的组成部分必须相同,这限制了其使用范围。
-
如果产品的内部变化复杂,该模式会增加很多的建造者类。
建造者(Builder)模式和工厂模式的关注点不同:建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。
- 点赞 19
- 收藏
- 分享
- 文章举报
- 一文带你读懂“技术系统演化模式”
- 一文让你读懂策略模式
- 一文唬住所有面试官:懒汉式单例模式中的线程安全问题
- 浅谈设计模式之建造者模式
- 设计模式Builder模式——java设计模式——建造者模式
- 设计模式读书笔记:Builder(建造者)
- 建造者模式
- 建造者(Builder)模式
- C++设计模式之建造者模式(改编自C++设计模式)
- 设计模式之建造者模式
- 设计模式之建造者模式
- 二、建造者模式_适配器设计模式
- go建造者模式,【go设计模式】
- 设计模式学习6——建造者模式
- 大话设计模式c++实现---建造者模式
- 【朝花夕拾】设计模式之建造者模式
- 一文读懂机器学习,大数据/自然语言处理/算法全有了
- 设计模式--建造者模式
- 建造者模式
- 设计模式那点事--建造者模式