[设计模式] - 建造者模式

一、建造者模式的简介

1. 什么是建造者模式

建造者模式(Builder Pattern) 隶属于创建型设计模式,是一种通过将多个简单对象或属性一步一步构建成一个复杂对象的设计手段。建造者模式力图将对象的业务与创建分离,使得通过不同的创建方式搭配可以形成不同的业务对象。

2. 建造者模式使用的业务场景

不知道小伙子们小时候有没有玩过芭比娃娃,芭比娃娃无疑是最适合讲述建造者模式的业务场景。同一款芭比娃娃我们可以通过给它更换不同的服装或配饰达到让其外观不同的效果。就比如我们先设定一款芭比娃娃拥有三个固有属性:

  1. 发型
  2. 裙子

我们要做的就是通过改变这三种属性的搭配来使我们的芭比看起来不太一样。

二、传统方式实现

1. 利用有参构造

在讲述建造者模式的实现之前,我们还是先看下利用传统方式如何实现一个芭比换装的效果呢?最简单的方式应该就是利用有参构造:

public class BarbieDoll {
    
    

	private String hair;

	private String dress;

	private String shoes;

	public BarbieDoll() {
    
    
		super();
		// TODO Auto-generated constructor stub
	}

	public BarbieDoll(String hair, String dress, String shoes) {
    
    
		super();
		this.hair = hair;
		this.dress = dress;
		this.shoes = shoes;
	}

	@Override
	public String toString() {
    
    
		return "BarbieDoll [hair=" + hair + ", dress=" + dress + ", shoes=" + shoes + "]";
	}

	public String getHair() {
    
    
		return hair;
	}

	public void setHair(String hair) {
    
    
		this.hair = hair;
	}

	public String getDress() {
    
    
		return dress;
	}

	public void setDress(String dress) {
    
    
		this.dress = dress;
	}

	public String getShoes() {
    
    
		return shoes;
	}

	public void setShoes(String shoes) {
    
    
		this.shoes = shoes;
	}

}

测试代码:

public class Collocation {
    
    

	public static void main(String[] args) {
    
    

		BarbieDoll barbieDoll = new BarbieDoll("白色的头发", "黑色的长裙", "褐色的小皮鞋");
		System.out.println(barbieDoll.toString());

	}

}

测试结果:
在这里插入图片描述
那么我们分析下利用有参构造的方式有什么优劣势呢?
优点:

  1. 简单,就真的很简单。我们只需要利用实体本身的有参构造然后传入不同的参数就可以实现一个对象的构建。

缺点:

  1. 首先来说第一个缺点就是代码的复用性不好。每一次我要在业务中创建同种类的对象都需要重新传入一遍参数,复用性极差。
  2. 第二点就是如果我们创建的都是这种简单对象的话,这种方式可能问题不大,但是如果此时对象内部属性过于复杂,就比如我们为芭比实体添加一个引用类型的属性:朋友,那么这个类通过有参构造创建的工作量就会指数型的提升。

那么为了解决上述的问题,我们就可以使用建造者模式了。(别说其他方式也能解决,解决了我还怎么给你们讲建造者模式!!!!)

三、建造者模式实现

建造者模式主要分为四个部分组成:

  1. 产品对象 product
  2. 流程制定者 builder
  3. 细节实现者 concreteBuilder
  4. 决策者 director

第一步: 创建产品对象

public class BarbieDoll {
    
    

	private String hair;

	private String dress;

	private String shoes;

	private BarbieDoll friend;

	public BarbieDoll() {
    
    
		super();
		// TODO Auto-generated constructor stub
	}

	public BarbieDoll(String hair, String dress, String shoes, BarbieDoll friend) {
    
    
		super();
		this.hair = hair;
		this.dress = dress;
		this.shoes = shoes;
		this.friend = friend;
	}

	public String getHair() {
    
    
		return hair;
	}

	public void setHair(String hair) {
    
    
		this.hair = hair;
	}

	public String getDress() {
    
    
		return dress;
	}

	public void setDress(String dress) {
    
    
		this.dress = dress;
	}

	public String getShoes() {
    
    
		return shoes;
	}

	public void setShoes(String shoes) {
    
    
		this.shoes = shoes;
	}

	public BarbieDoll getFriend() {
    
    
		return friend;
	}

	public void setFriend(BarbieDoll friend) {
    
    
		this.friend = friend;
	}

	@Override
	public String toString() {
    
    
		return "BarbieDoll [hair=" + hair + ", dress=" + dress + ", shoes=" + shoes + ", friend=" + friend + "]";
	}

}

第二步: 创建Builder接口

public interface BarbieBuilder {
    
    

	void hair();

	void dress();

	void shoes();

	void friend();

	BarbieDoll getResult();

}

第三步: 创建concreteBuilder

这里我分别创建男性芭比和女性芭比两种实现
女性芭比

public class LadyBarbieBuilder implements BarbieBuilder {
    
    

	private BarbieDoll barbieDoll = new BarbieDoll();

	@Override
	public void hair() {
    
    
		barbieDoll.setHair("红色长发");

	}

	@Override
	public void dress() {
    
    
		barbieDoll.setDress("黑色长裙");

	}

	@Override
	public void shoes() {
    
    
		barbieDoll.setShoes("褐色小皮鞋");

	}

	@Override
	public void friend() {
    
    
		barbieDoll.setFriend(null);

	}

	@Override
	public BarbieDoll getResult() {
    
    
		return barbieDoll;

	}

}

男性芭比

public class BoyBarbieDollBuilder implements BarbieBuilder {
    
    

	private BarbieDoll barbieDoll = new BarbieDoll();

	@Override
	public void hair() {
    
    
		barbieDoll.setHair("黑色短发");

	}

	@Override
	public void dress() {
    
    
		barbieDoll.setDress("黑色夹克");

	}

	@Override
	public void shoes() {
    
    
		barbieDoll.setShoes("aj黑脚趾");

	}

	@Override
	public void friend() {
    
    
		barbieDoll.setFriend(null);

	}

	@Override
	public BarbieDoll getResult() {
    
    

		return barbieDoll;
	}

}

第四步: 创建directory

public class BarbieDollDirector {
    
    

	private BarbieBuilder barbieBuilder;

	public BarbieDollDirector(BarbieBuilder barbieBuilder) {
    
    
		super();
		this.barbieBuilder = barbieBuilder;
	}

	public BarbieDoll makeBarbieDoll() {
    
    
		barbieBuilder.hair();
		barbieBuilder.dress();
		barbieBuilder.shoes();
		return barbieBuilder.getResult();
	}
}

第五步:测试结果

public class MakeBarbieDoll {
    
    
	public static void main(String[] args) {
    
    
		BarbieDollDirector ladyDirector = new BarbieDollDirector(new LadyBarbieBuilder());
		BarbieDollDirector boyDirector = new BarbieDollDirector(new BoyBarbieDollBuilder());
		BarbieDoll lady = ladyDirector.makeBarbieDoll();
		BarbieDoll boy = boyDirector.makeBarbieDoll();
		System.out.println(lady.toString());
		System.out.println(boy.toString());
	}
}

在这里插入图片描述

四、 建造者模式的实现原理

如果你看了代码没有明白,我觉得是一件很正常的现象。我们接下来要做的就是要分析下为什么要这么写。

1. 建造者模式的角色构成

在这里插入图片描述
这里我们可以将建造者模式分为五个部分

  1. product: 产品本身,这里的产品不需要关注创建流程及属性制定。
  2. Builder: 建造者顶级接口,负责制定整个创建流程,但不会实现细节
  3. concreteBuilder: 建造者实现类,负责这个创建流程的细节实现
  4. director: 决策者,负责隔离产品属性与产品创建流程,控制整个产品的创建过程。
  5. service: 业务调用方,通过为director传入不同的builder实现生产不同的产品。

2. 建造者模式的特点

那么为什么我们要将一个简单的产品创建拆分成这么多步呢?首先,建造者模式实现了产品与创建细节分离,产品本身不会与创建细节耦合,这样在创建细节发生变动的时候,我们无需更改产品相关的代码,符合开闭原则。第二点,我们将创建细节抽离出来,很大程度上的提高了代码的复用性,下次在遇到需要创建相同对象的时候,只需要传入对应的builder和director即可。第三点,如果当我们的产品需求发生了改变,我们只需要创建新的builder实现或在director中添加新的流程即可,依旧是温和开闭原则的可拓展性。
那么简单的来说,建造模式的特点如下:
优点:

  1. 符合开闭原则,可拓展性好。
  2. 业务与产品解耦合,实现了可插拔效果。
  3. 便于控制细节特点。

缺点:

  1. 产品之间必须拥有共同点,使用范围受限
  2. 如果内部实现变动过多,需要创建很多新的子类来完成

好了,今天的内容到此结束,如果还有疑问的同学可以私信我或在评论区留言,我会在第一时间为你解答。觉得有收获的小伙伴请记得一键三连,关注博主不要走丢,拒当白嫖党~

猜你喜欢

转载自blog.csdn.net/xiaoai1994/article/details/112648273