DesignPattern - 建造者模式【创建型】
# 一、建造者模式介绍
建造者模式(Builder Pattern)使用多个简单的步骤一步步构建成一个复杂的对象,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建出不同的实例;允许用户只通过指定复杂对象的类型和内容就可以构建它们,不需要知道内部的具体构建细节。
核心组成
Product:产品角色
Builder:抽象建造者,定义多个通用方法和构建方法
ConcreteBuilder:具体建造者,可以有多个
Director:指挥者,控制整个组合过程,将需求交给建造者,由建造者去创建对象
补充:核心组成不一定要全部齐全,比如 Director 通常可以省略,可参考 java 中的 StringBuilder 也是建造者模式(不完全一样,但思想一致)
场景举例
- KFC 创建套餐:套餐是一个复杂对象,它一般包含 主食如汉堡、烤翅 和 饮料如果汁、可乐等 组成部分,不同的套餐有不同的组合,而 KFC 的服务员可以根据顾客的要求,一步一步装配这些组成部分,构造一份完整的套餐
- 电脑组装:有低配、高配,根据用户需求,采购不同规格的 CPU、内存、电源、硬盘、主板等。
优点
- 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦
- 每一个具体建造者都相对独立,而与其他的具体建造者无关,更加精细地控制产品的创建过程
- 增加新的具体建造者无须修改原有类库的代码,符合开闭原则
- 建造者模式结合链式编程来使用,代码上更加美观
缺点
- 建造者模式所创建的产品一般具有较多的共同点,如果产品差异大则不建议使用
建造者模式与抽象工厂模式的比较:
- 建造者模式返回一个组装好的完整产品
- 抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成一个产品族
# 二、建造者模式代码实现
创建产品类:
/**
* 套餐
*
* @author GitLqr
*/
public class SetMenu {
// 主食
private String stapleFood;
// 饮料
private String drink;
// 小吃
private String snack;
public SetMenu(String stapleFood, String drink, String snack) {
super();
this.stapleFood = stapleFood;
this.drink = drink;
this.snack = snack;
}
@Override
public String toString() {
return "SetMenu [stapleFood=" + stapleFood + ", drink=" + drink + ", snack=" + snack + "]";
}
}
创建抽象建造者类(或接口):
/**
* 套餐建造接口
*
* @author GitLqr
*/
public interface ISetMenuBuilder {
ISetMenuBuilder addStapleFood(String stapleFood);
ISetMenuBuilder addDrink(String drinkString);
ISetMenuBuilder addSnak(String snak);
SetMenu build();
}
创建具体建造者类:
/**
* KFC 套餐建造器
*
* @author GitLqr
*/
public class KFCSetMenuBuilder implements ISetMenuBuilder {
private List<String> stapleFoods = new ArrayList<>();
private List<String> drinks = new ArrayList<>();
private List<String> snaks = new ArrayList<>();
@Override
public ISetMenuBuilder addStapleFood(String stapleFood) {
this.stapleFoods.add(stapleFood);
return this;
}
@Override
public ISetMenuBuilder addDrink(String drink) {
this.drinks.add(drink);
return this;
}
@Override
public ISetMenuBuilder addSnak(String snak) {
this.snaks.add(snak);
return this;
}
@Override
public SetMenu build() {
return new SetMenu(stapleFoods.toString(), drinks.toString(), snaks.toString());
}
}
说明:【具体建造者类】可以拓展出很多个,比如 "永和豆浆" 的套餐建造者 YonHoSetMenuBuilder 等等。
创建指挥者类(Director):
/**
* KFC 指挥者(服务员)
*
* @author GitLqr
*/
public class KFCDirector {
public static SetMenu getBreakfastSetMenu() {
return new KFCSetMenuBuilder()
.addStapleFood("皮蛋瘦肉粥")
.addDrink("豆浆")
.build();
}
public static SetMenu getFamilyBucketSetMenu() {
return new KFCSetMenuBuilder()
.addStapleFood("香辣鸡腿堡")
.addStapleFood("新奥尔良烤鸡腿堡")
.addDrink("百事可乐")
.addDrink("美年达")
.addSnak("吮指原味鸡")
.addSnak("新奥尔良烤翅")
.addSnak("葡式蛋挞")
.addSnak("醇香土豆泥")
.build();
}
}
说明:实际开发中,指挥者类(Director)很多时候会被省略掉,取而代之,由使用者在业务代码中 使用【具体建造者类】直接创建产品,这让产品的创建更加灵活,但同时也增加了不可控性,需根据实际情况权衡利弊。
使用:
public class Test {
public static void main(String[] args) {
SetMenu breakfast = KFCDirector.getBreakfastSetMenu();
SetMenu familyBucket = KFCDirector.getFamilyBucketSetMenu();
System.out.println("KFC早餐套餐:" + breakfast);
System.out.println("KFC全家桶套餐:" + familyBucket);
}
}
- 01
- Flutter - 危!3.24版本苹果审核被拒!11-13
- 02
- Flutter - 轻松搞定炫酷视差(Parallax)效果09-21
- 03
- Flutter - 轻松实现PageView卡片偏移效果09-08