设计模式(java)- 建造者模式

1. 简介

  建造者模式,借用百度百科的解释:建造者模式是设计模式的一种,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
  如上,可以看出来建造者模式属于创建型模式的一种,它的作用主要是:

  1. 将类对象的创建过程和细节封装起来,客户代码只需要知道自己建造对象的建造者是谁就可以获取到自己需要的类对象。
  2. 根据客户代码的需求可以通过相同的创建顺序和逻辑创建出拥有相同成员类型但是不同成员值的类对象。

2. 类图

  UML是帮助我们理解设计模式最好的工具,下面是一个基本的创建者模式的设计类图:
在这里插入图片描述
  如上对类图的各个模块进行说明:

  1. 指挥者类Direct,暴露给客户的类,客户创建一个对象时只需要与这个类交互就可以。
  2. 指挥类是提供给客户的接口类,指挥者中的接口一般是构建产品的方法,该方法的形参一般是具体的构建者对象。所以客户还需要关注的是构建者类(类似于工厂类),它就是客户的需求类,客户需要什么样的产品就传入对应的构建者类对象。
  3. 构建者类,拥有共同的抽象接口(IBuilder),根据不同的产品部件设计不同的创建者类(ConcretelBuilder)
  4. 产品类(Product),最终客户需要的产品对象,具体有构建者类进行构建。

3. 实例

3.1 场景

  一家手机代理制造商,自然有自己的手机制造工厂,类似于富士康。手机产品公司A要求代理商生产出如下的产品参数的手机。

CPU: Qualcomm Snapdragon 845
RAM: 8GB
ROM: 64GB
Battery: 3400mAh
Screen: Corning Gorilla Sixth Generation Screen
System: android8.1

3.2 代码实例

3.2.1 产品类

  根据如上的场景,我们可以设计一个手机产品类如下:

class EPhone {
	private String cpu;
	private String ram;
	private String rom;
	private String battery;
	private String screen;
	private String system;
	
	public EPhone() {
		this.cpu = "";
		this.ram = "";
		this.rom = "";
		this.battery = "";
		this.screen = "";
		this.system = "";
	}
	
	public void setCpu(String strCpu) {
		this.cpu = strCpu;
	}
	
	public void setRam(String strRam) {
		this.ram = strRam;
	}
	
	public void setRom(String strRom) {
		this.rom = strRom;
	}
	
	public  void setBattery(String strBattery) {
		this.battery = strBattery;
	}
	
	public void setScreen(String strScreen) {
		this.screen = strScreen;
	}
	
	public void setSystem(String strSystem) {
		this.system = strSystem;
	}
	
	public String getSystem() {
		return this.system;
	}
	//...
}

  该例子主要为了说明创建者模式,所以会省略一些代码。

3.2.1 创建者类

  有了产品类,那么需要一个建造者类,用于对产品的具体构建,这一步主要作用的封装产品的构建逻辑,以及根据产品需求不同的产品部件(部件类型相同,主要体现在部件的内部属性或逻辑),设计不同的建造类。
   根据以上的说明,建者者类有许多,所以需要抽象接口类或抽象类。

interface IPhoneBuilder {
	public void buildCpu();
	public void buildRam();
	public void buildRom();
	public void buildBattery();
	public void buildScreen();
	public void buildSystem();
	public EPhone createPhone();
}

  如上,建造者接口提供了建造产品各个部件的方法,以及最终生产出具体产品的方法:

public EPhone createPhone()

  下面代理商就需要根据A手机公司设计具体的建造者类了,定位该手机为A手机公司的高配版:

class EHighVersionPhoneBuilder implements IPhoneBuilder {
	private EPhone highPhone = null;
	
	public EHighVersionPhoneBuilder() {
		highPhone = new EPhone();
	}
	
	public void buildCpu() {
		highPhone.setCpu("Use Qualcomm Snapdragon 845");
	}
	
	public void buildRam() {
		highPhone.setRam("Use 8GB RAM");
	}
	
	public void buildRom() {
		highPhone.setRom("Use 64GB ROM");
	}
	
	public void buildBattery() {
		highPhone.setBattery("Use 3400 mAh battery");
	}
	
	public void buildScreen() {
		highPhone.setScreen("Use Corning Gorilla Sixth Generation Screen");
	}
	
	public void buildSystem() {
		highPhone.setSystem("Use android8.1 operating system");
	}
	
	public EPhone createPhone() {
		return highPhone;
	}
}

3.2.2 指挥类

  创建类设计完成后,客户代码本可以直接根据建造者类直接得到自己所需要的产品对象,但是我们会发现这个时候客户需要知道该产品的构建顺序是什么样的,那么客户就会写下如下的代码:

EHighVersionPhoneBuilder highVersionPhoneBuilder = new EHighVersionPhoneBuilder();
highVersionPhoneBuilder .buildCpu();
highVersionPhoneBuilder .buildRam();
highVersionPhoneBuilder .buildRom();
highVersionPhoneBuilder .buildBattery();
highVersionPhoneBuilder .buildScreen();
highVersionPhoneBuilder .buildSystem();
highVersionPhoneBuilder .createPhone();

  问题来了,这么多个接口方法,如果构建顺序发生变化,客户就需要跟着去修改代码,如果这块代码在很多处都有使用,那改起来很麻烦,也违背了开闭原则。所以这个时候我们需要一个指挥者类,来控制产品构建的顺序。

class EPhoneDirector {
	public static EPhone createPhone(IPhoneBuilder phoneBuilder) {
		if (phoneBuilder != null) {
			phoneBuilder.buildCpu();
			phoneBuilder.buildRam();
			phoneBuilder.buildRom();
			phoneBuilder.buildBattery();
			phoneBuilder.buildScreen();
			phoneBuilder.buildSystem();
				
			return phoneBuilder.createPhone();
		}
		return null;
	}
}

3.2.3 客户调用

  如下是客户创建一个高配版手机的过程:

public class EBuilder {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		EHighVersionPhoneBuilder highVersionPhoneBuilder = new EHighVersionPhoneBuilder();
		EPhone highPhone = EPhoneDirector.createPhone(highVersionPhoneBuilder);
		System.out.println(highPhone.getSystem()); 
	}

}

  我们会发现需要客户需要获取一个产品对象,只需要关注两个类,一个是指挥者类,一个是具体的建造类。

3.2.4 实例扩展

  至此,一个建造者模式的基本架构就出来了,那么当A公司又需要一个低配版的手机,怎么办呢,我们只需要拿到A公司提供的低配版参数,创建一个低配版的建造类就可以了。同理,A公司需要一个NFC版本的手机,其他参数和高配版一样,那么手机类新增一个NFC的设计方法,高配构建者新增一个nfc的构建接口,然后在指挥类加一个构建NFC高配版的方法就可以了:

class EPhoneDirector {
	public static EPhone createNfcPhone(IPhoneBuilder phoneBuilder) {
		if (phoneBuilder != null) {
			phoneBuilder.buildCpu();
			phoneBuilder.buildRam();
			phoneBuilder.buildRom();
			phoneBuilder.buildBattery();
			phoneBuilder.buildScreen();
			phoneBuilder.buildSystem();
			phoneBuilder.buildNfc();	
			return phoneBuilder.createPhone();
		}
		return null;
	}
}

  在这个建造者模式的架构中,我们可以根据具体需求灵活的使用,这样客户对产品的构建就会很方便,方便了代码的重用性。

4. 总结

4.1 优缺点

优点:

  1. 解耦,低耦合。客户代码不需要关注产品的创建逻辑和顺序。
  2. 扩展性好,根据客户的需求,可以扩展不同的建造者类或者根据产品创建的顺序的不同,新增不同的指挥方法,符合开闭原则。
  3. 便于控制内部细节和逻辑,便于维护。

缺点:

  1. 局限性:产品本身的局限性,一般需要构建的产品之间又相同或较多的共同点,产品的组成结构相同。这种局限性使得建造者模式的使用场景相对较少,当产品的差异性很大时,例如手机和电脑,这样则不适合使用该模式。
  2. 有类膨胀的理论风险:当产品类型很多时,我们就需要设计多个建造者类,这样会造成类过多的问题,该问题同样体现在工厂方法中。但是一班情况下不会出现这种情况。

  以上就是我对创建者模式的理解,创建者模式很少在项目中使用,但是如果遇到具体的业务,使用它还是会很方便我们程序的设计。总之具体问题具体分析,能够根据不同的业务场景来使用不同的设计模式,那就是好的设计。

设计模式代码:
https://github.com/eaikao/DesignPatterns.git

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

非正经程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值