建造者模式:一个打工人的一天

一个打工人的一天

早晨,早高峰,一路突突突到公司,还好没迟到。一上午,小曾噼里啪啦地敲键盘,早上忘记吃早餐,肚子好饿,终于扛到中午。
于是乎,一路奔赴食堂。食堂窗口有10来个菜,不过大多数人是点套餐,因为划得来。一荤一素一汤,好吃不贵。点好套餐后,选择自己喜欢吃的菜,就找个空位,开始就餐。
小曾边吃饭边想:是不是可以简化这个点餐过程呢?
顾客自助,根据套餐:一荤一素一汤,自己打菜。
定义一荤一素一汤的A套餐:

/**
 * A套餐
 * @author zherop
 */
public class SubMealA {
	private String meat; // 肉类
	private String vegetable; // 蔬菜类
	private String drink; // 饮品类

	public String getMeat() {
		return meat;
	}

	public void setMeat(String meat) {
		this.meat = meat;
	}

	public String getVegetable() {
		return vegetable;
	}

	public void setVegetable(String vegetable) {
		this.vegetable = vegetable;
	}

	public String getDrink() {
		return drink;
	}

	public void setDrink(String drink) {
		this.drink = drink;
	}

	@Override
	public String toString() {
		return "SubMealA [meat=" + meat + ", vegetable=" + vegetable + ", drink=" + drink + "]";
	}
}

场景类:

/**
 * 场景类
 * 
 * @author zherop
 */
public class Client {
	public static void main(String[] args) {
		SubMealA subMealA = new SubMealA();
		subMealA.setMeat("青椒炒肉");
		subMealA.setVegetable("生菜");
		subMealA.setDrink("紫菜蛋汤");
		System.out.println(subMealA);
	}
}

// SubMealA [meat=青椒炒肉, vegetable=生菜, drink=紫菜蛋汤]

顾客想要A套餐,然后根据A套餐所包含的3部分,分别在每一类可选的范围内,进行选择。什么都要知道,是不是感觉吃个饭怎么就这么难啊。
为了改进这个过程,打菜阿姨登场。

/**
 * A套餐建造者,就是打菜的阿姨
 * @author zherop
 */
public class SubMealABuilder {
	private SubMealA subMealA;

	public SubMealABuilder() {
		this.subMealA = new SubMealA();
	}

	private void buildMeat() {
		subMealA.setMeat("青椒炒肉");
	}

	private void buildVegetable() {
		subMealA.setVegetable("生菜");
	}

	private void buildDrink() {
		subMealA.setDrink("紫菜蛋汤");
	}

	public void build() {
		buildMeat();
		buildVegetable();
		buildDrink();
    }

	public SubMealA getSubMealA() {
		return subMealA;
	}
}

场景类变成了这样:

/**
 * 场景类
 * 
 * @author zherop
 */
public class Client {
	public static void main(String[] args) {
		SubMealABuilder subMealABuilder = new SubMealABuilder();
		subMealABuilder.build();
		SubMealA subMealA = subMealABuilder.getSubMealA();
		System.out.println(subMealA);
	}
}
// SubMealA [meat=青椒炒肉, vegetable=生菜, drink=紫菜蛋汤]

顾客不用再关心套餐里的东西怎么来的,只需要找到负责A套餐的打菜阿姨就行。
但是老是吃这几个菜,一荤一素一汤套餐,想换其他类别的怎么办呢?
既然A套餐,包含多种组合,那么定义一个A套餐的建造规范:

/**
 * A套餐建造规范
 * @author zherop
 */
public abstract class AbstractSubMealABuilder {
	protected SubMealA subMealA;

	public AbstractSubMealABuilder() {
		this.subMealA = new SubMealA();
	}

	protected abstract void buildMeat();

	protected abstract void buildVegetable();

	protected abstract void buildDrink();

	public void build() {
		buildMeat();
		buildVegetable();
		buildDrink();
	}

	public SubMealA getSubMealA() {
		return subMealA;
	}
}

A套餐的有两个负责打菜的阿姨:

/**
 * 负责A套餐1号的阿姨
 * 
 * @author zherop
 *
 */
public class SubMealA1Builder extends AbstractSubMealABuilder {

	@Override
	protected void buildMeat() {
		this.subMealA.setMeat("青椒炒肉");
	}

	@Override
	protected void buildVegetable() {
		this.subMealA.setVegetable("生菜");
	}

	@Override
	protected void buildDrink() {
		this.subMealA.setDrink("紫菜蛋汤");
	}

}

/**
 * 负责A套餐2号的阿姨
 * @author zherop
 */
public class SubMealA2Builder extends AbstractSubMealABuilder {

	@Override
	protected void buildMeat() {
		this.subMealA.setMeat("孜然牛肉");
	}

	@Override
	protected void buildVegetable() {
		this.subMealA.setVegetable("空心菜");
	}

	@Override
	protected void buildDrink() {
		this.subMealA.setDrink("冬瓜排骨汤");
	}

}

场景类变成了这样:

/**
 * 场景类
 * 
 * @author zherop
 */
public class Client {
	public static void main(String[] args) {
		// 选择A套餐1号
		// AbstractSubMealABuilder subMealABuilder = new SubMealA1Builder();
		// 选择A套餐2号
		AbstractSubMealABuilder subMealABuilder = new SubMealA2Builder();
		subMealABuilder.build();
		SubMealA subMealA = subMealABuilder.getSubMealA();
		System.out.println(subMealA);
	}
}
// SubMealA [meat=孜然牛肉, vegetable=空心菜, drink=冬瓜排骨汤]

这个时候,想要A套餐1号菜,就找1号打菜阿姨,想要A套餐2号菜,就找2号打菜的阿姨就行。
似乎一些都还不错,可能是已经习惯了,但是习惯的东西不见得合理。现在想吃什么套餐,需要拿着空餐盘,去找对应的阿姨打菜,等他们打好菜(subMealABuilder.build()),再把餐盘给我们,必须要先打好菜,再把餐盘给我们才有意义。
我们再来改进下,这个时候小姐姐(前台服务员)登场。

/**
 * 前台服务员
 * 
 * @author zherop
 *
 */
public class FrontWaiter {
	
	private AbstractSubMealABuilder subMealA1Builder;
	
	public void setSubMealA1Builder(AbstractSubMealABuilder subMealA1Builder) {
		this.subMealA1Builder = subMealA1Builder;
	}
	
	/**
	 * 获取A套餐
	 * 
	 * @return
	 */
	public SubMealA getSubMealA1() {
		subMealA1Builder.build();
		return subMealA1Builder.getSubMealA();
	}

}

这个时候场景类变成了这样:

/**
 * 场景类
 * @author zherop
 */
public class Client {
	public static void main(String[] args) {
		FrontWaiter frontWaiter = new FrontWaiter();
		// 告诉服务员,我要点A套餐1号
		frontWaiter.setSubMealA1Builder(new SubMealA1Builder());
		// 告诉服务员,我要点A套餐2号
        // frontWaiter.setSubMealA1Builder(new SubMealA2Builder());
		SubMealA subMealA1 = frontWaiter.getSubMealA1();
		System.out.println(subMealA1);
	}
}

这下,顾客只需要跟前台服务员打交道了,再也不用拿着空餐盘,去让打菜阿姨打菜了。直接告诉前台服务员,顾客想要什么套餐,然后服务员就直接给了,不用再操心那么多了。如果后续A套餐还有其他系列,比如3号、4号…,直接新增对应的打菜阿姨,然后顾客直接告诉前台服务员需要的系列即可,而对于顾客来说整个过程没有什么变化。

好了,饭也吃完了,回公司。午休,敲键盘5小时候后,下班。

定义

建造者模式定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
涉及角色:

  1. 抽象建造者(Builder)
    为创建一个产品对象的各个部件定义抽象接口 ,一般会有两类方法:一类是buildPartXXX(),由于创建各个部件,一类是方法是getResult(),返回复杂产品对象。抽象建造者可以是抽象类,也可以是接口。比如故事中的AbstractSubMealABuilder。
  2. 具体建造者(ConcreteBuilder)
    实现抽象建造者定义的接口,即实现各个部件的具体创建。比如故事中的SubMealA1Builder、SubMealA2Builder
  3. 产品(Product)
    被构建的复杂对象,包含多个部件。比如故事中的SubMealA。
  4. 指挥者(Director)
    负责安排复杂对象的建造次序,对客户端而言,不需要再关心各个部件创建的顺序。比如故事中的FrontWaiter。
    类图:
    在这里插入图片描述

适用场景

  1. 需要生成的产品对象有复杂的内部结构,通过包含多个成员属性。
  2. 需要生成的产品对象的属性相互依赖,需要指定各个属性的生成顺序。
  3. 隔离复杂对象的创建和使用。

扩展

  1. 如果具体建造者只有一个时,可以省略抽象建造者;
  2. 如果复杂对象的各个部件的生成顺序,关系不大,这个时候也可以考虑省略指挥者。

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值