23种设计模式笔记第四篇建造者模式(参考狂神视频)

建造者模式也是创建型模式(帮助我们省去new的过程,更好的创建对象)

建造者模式提供了一种创建对象的最佳方式。

定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

主要作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。

用户只需要给出指定复杂对象的类型和内容,建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)

例子:

工厂(建造者模式)∶负责制造汽车(组装过程和细节在工厂内)

汽车购买者(用户)∶你只需要说出你需要的型号(对象的类型和内容),然后直接购买就可以使用了(不需要知道汽车是怎么组装的(车轮、车门、发动机、方向盘等等))

常规用法(第一种)

角色:抽象建造者(Builder),具体建造者(ConcreteBuilder),指挥者(Director),具体的产品(Product)

我们用一张图来看就会清晰很多:

抽象的建造者,不负责具体的建造,只是定义一些方法跟接口(或者说是步骤)。然后我们有了具体的产品之后,就需要去建造它。完工之后抽象的建造者就可以得到一个产品。建造它需要使用具体的建造类,具体的建造类只需要完成那些步骤,然后返回具体的产品就好了。一个抽象的建造者可以有很多不同的具体建造者。

需要注意的是,产品是由具体的建造者来生产的,也就是说我们要再具体的建造者类的构造方法中去new一个产品对象。

指挥者是核心,负责指挥构建一个工程,工程如何构建,由它决定。指挥者最后要指挥具体的建造者,指挥工人按照顺序建房子。控制调用先后顺序,并向调用者返回完整的产品类

最后用一句话描述就是:指挥者负责指挥建造者生产具体的产品

以建房子为例:

首先我们需要一个抽象的建造者类,去定义一些建造房子的步骤方法,并且给定一个得到具体产品的方法

//抽象的建造者,定义建房子的步骤
public abstract class Builder {
	abstract void buildA();//地基
	abstract void buildB();//钢筋工程
	abstract void buildC();//铺电线
	abstract void buildD();//粉刷
	
	//完工:得到产品
	abstract Product getProduct();
	
}

然后我们需要一个具体的房子类

//产品:房子
public class Product {

	private String buildA;
	private String buildB;
	private String buildC;
	private String buildD;
	
	public String getBuildA() {
		return buildA;
	}
	public void setBuildA(String buildA) {
		this.buildA = buildA;
	}
	public String getBuildB() {
		return buildB;
	}
	public void setBuildB(String buildB) {
		this.buildB = buildB;
	}
	public String getBuildC() {
		return buildC;
	}
	public void setBuildC(String buildC) {
		this.buildC = buildC;
	}
	public String getBuildD() {
		return buildD;
	}
	public void setBuildD(String buildD) {
		this.buildD = buildD;
	}
	@Override
	public String toString() {
		return "Product [buildA=" + buildA + ", buildB=" + buildB + ", buildC=" + buildC + ", buildD=" + buildD + "]";
	}
	
}

有了具体的房子之后我们就需要去建造它,也就是具体的建造类

//具体的建造者:工人
public class Worker extends Builder {
	private Product product;
	public Worker() {
		//这里至关重要,工人负责创建产品
		this.product = new Product();
	}
	@Override
	void buildA() {
		product.setBuildA("地基");
		System.out.println("地基");
	}

	@Override
	void buildB() {
		product.setBuildB("钢筋");
		System.out.println("钢筋");
	}

	@Override
	void buildC() {
		product.setBuildC("铺电线");
		System.out.println("铺电线");
	}

	@Override
	void buildD() {
		product.setBuildD("粉刷");
		System.out.println("粉刷");
	}

	@Override
	Product getProduct() {
		return product;
	}

}

指挥房子创建的过程,在指挥者类中定义实现的顺序

//指挥者:核心,负责指挥构建一个工程,工程如何创建,由它决定
public class Director {

	//指挥工人按照顺序建房子
	//核心的顺序是在这个方法中
	public Product build(Builder builder) {
		builder.buildA();
		builder.buildB();
		builder.buildC();
		builder.buildD();
		return builder.getProduct();
	}
}

测试一下

public class Test {
	public static void main(String[] args) {
		//指挥
		Director director = new Director();
		//指挥具体的工人完成产品
		Product build = director.build(new Worker());
		System.out.println(build.toString());
	}
}

结果:

假设有不一样的工人就可以创建不一样的楼房

上面示例是Builder模式的常规用法,指挥者类Director在Builder模式中具有很重要的作用,它用于指导具体构建者如何构建产品,控制调用先后次序,并向调用者返回完整的产品类,但是有些情况下需要简化系统结构,可以把Director和抽象建造者进行结合。

为了使建造者模式更加灵活,要将指挥者给用户(第二种)

通过静态内部类方式实现零件无序装配构造,这种方式使用更加灵活,更符合定义。内部有复杂对象的默认实现,使用时可以根据用户需求自由定义更改内容,并且无需改变具体的构造方式。就可以生产出不同复杂产品。使用链式编程

来看具体的案例:

首先创建一个抽象建造者

//抽象的建造者
public abstract class Builder {
	abstract Builder buildA(String msg);//汉堡
	abstract Builder buildB(String msg);//可乐
	abstract Builder buildC(String msg);//薯条
	abstract Builder buildD(String msg);//甜点
	
	//完工:得到套餐
	abstract Product getProduct();
	
}

然后创建一个产品,给定默认值

//产品:套餐
public class Product {
	
	//默认套餐
	private String buildA = "汉堡";
	private String buildB = "可乐";
	private String buildC = "薯条";
	private String buildD = "甜点";

	public void setBuildA(String buildA) {
		this.buildA = buildA;
	}
	public void setBuildB(String buildB) {
		this.buildB = buildB;
	}
	public void setBuildC(String buildC) {
		this.buildC = buildC;
	}
	public void setBuildD(String buildD) {
		this.buildD = buildD;
	}
	@Override
	public String toString() {
		return "Product [buildA=" + buildA + ", buildB=" + buildB + ", buildC=" + buildC + ", buildD=" + buildD + "]";
	}
	
}

编写具体的建造者

//具体的建造者
public class Worker extends Builder {
	private Product product;
	public Worker() {
		//这里至关重要,工人负责创建产品
		this.product = new Product();
	}
	@Override
	Builder buildA(String msg) {
		product.setBuildA(msg);
		return this;
	}
	@Override
	Builder buildB(String msg) {
		product.setBuildA(msg);
		return this;
	}
	@Override
	Builder buildC(String msg) {
		product.setBuildA(msg);
		return this;
	}
	@Override
	Builder buildD(String msg) {
		product.setBuildA(msg);
		return this;
	}
	@Override
	Product getProduct() {
		return product;
	}
	
}

使用链式编程测试

public class Test {
	public static void main(String[] args) {
		//服务员
		Worker worker = new Worker();
		//链式编程
		Product product = worker.buildA("全家桶").getProduct();
		System.out.println(product.toString());
	}
}

结果:

 就是顺序交到了客户手里,更加灵活自由,在原来的基础上可以自由组合,就算不组合也有默认的。

建造者与抽象工厂模式的区别

工厂模式关注的是创建单个产品,而建造者模式则关注创建复合对象,多个部分。

 建造者模式优点:

1、客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象

 2、每一个具体建造者都相对独立,与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,扩展方便,符合开闭原则

 3、可以更加精细地控制产品的创建过程

建造者模式缺点:

1、建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,不适合使用建造者模式,因此其使用范围受到一定的限制

2、如果产品的内部变化复杂,可能会需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加了系统的理解难度和运行成本

在以下情况下可以使用建造者模式:

1、需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员变量

2、需要生成的产品对象的属性相互依赖,需要指定其生成顺序

3、对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类和客户类中

4、隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品

写代码理解是最快的,看太多理论知识反而容易适得其反。

猜你喜欢

转载自blog.csdn.net/qq_44709970/article/details/124393224