场景
- 由于上次包装问题,水果店的生意越来越差,于是peter推出了各类水果套餐促销活动
- 虽然推出了促销活动但是问题也接着来了。比如针对不同的客户,套餐的水果组合也各不相同,只会越来越复杂,推出不同的套餐。于是每一个套餐就需要一个专门管理套餐的人,但是善于思考的peter发现虽然套餐不同,但是每一个套餐的创建过程基本是一样的。于是peter就把套餐的配置交给了店里的专业人员(老员工)来指挥,普通人员来配置,而且订单在结算套餐时,算法与具体套餐无关。这样一来不管是一种套餐分不同的促销活动还是不同的套餐分不同的促销活动,就只需要2名人员就能配好,又节约了一笔成本。
建造者模式
定义
指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。
结构
-
产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个部件。
-
抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。
-
具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。
-
指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建。
UML类图
代码实现
实现
套餐类(产品角色)
/**
* 创建一个水果套餐Meal类
*/
public class FruitMeal {
private Apple apple;//苹果价格
private Banana banana;//香蕉价格
private Orange orange;//桔子价格
private int discount;//折扣价,折扣价格对一个套餐来说,是固定的
private int totalPrice;//套餐总价
public void setDiscount(int discount) {
this.discount = discount;
}
public void setApple(Apple apple) {
this.apple = apple;
}
public void setBanana(Banana banana) {
this.banana = banana;
}
public void setOrange(Orange orange) {
this.orange = orange;
}
public int cost(){
return this.totalPrice;
}
public void init() {
if (null != apple){
totalPrice += apple.price();
}
if (null != orange){
totalPrice += orange.price();
}
if (null != banana){
totalPrice += banana.price();
}
if (totalPrice > 0){
totalPrice -= discount;
}
}
}
套餐建造者(抽象建造者)
/**
* 创建一个套餐Builder类,实际的builder类负责创建套餐Meal对象
*/
public interface Builder {
//设置苹果价格
void buildApple(int price);
//设置香蕉价格
void buildBanana(int price);
//设置桔子价格
void buildOrange(int price);
//返回创建的套餐,即getResult()
FruitMeal getFruitMeal();
}
具体套餐(具体建造者)
/**
* 假日套餐
*/
public class HolidayBuilder implements Builder {
private FruitMeal fruitMeal = new FruitMeal();
@Override
public void buildApple(int price) {
fruitMeal.setApple(new Apple(price));
}
@Override
public void buildBanana(int price) {
fruitMeal.setBanana(new Banana(price));
}
@Override
public void buildOrange(int price) {
fruitMeal.setOrange(new Orange(price));
}
@Override
public FruitMeal getFruitMeal() {
//假日套餐折扣
fruitMeal.setDiscount(10);
fruitMeal.init();
return fruitMeal;
}
}
/**
* Vip套餐
*/
public class VipBuilder implements Builder {
private FruitMeal fruitMeal = new FruitMeal();
@Override
public void buildApple(int price) {
fruitMeal.setApple(new Apple(price));
}
@Override
public void buildBanana(int price) {
fruitMeal.setBanana(new Banana(price));
}
@Override
public void buildOrange(int price) {
fruitMeal.setOrange(new Orange(price));
}
@Override
public FruitMeal getFruitMeal() {
//Vip套餐折扣
fruitMeal.setDiscount(15);
fruitMeal.init();
return fruitMeal;
}
}
客户端调用
public class TestClient {
public static void main(String[] args) {
//指挥者
//Builder builder = new HolidayBuilder();
Builder builder = new VipBuilder();
builder.buildApple(100);
builder.buildBanana(50);
builder.buildOrange(100);
FruitMeal fruitMeal = builder.getFruitMeal();
int cost = fruitMeal.cost();
System.out.println("优惠后的套餐价格为--->" + cost);
}
}
结果
优惠后的套餐价格为--->235
优缺点
优点
- 各个具体的建造者相互独立,有利于系统的扩展。
- 客户端不必知道产品内部组成的细节,便于控制细节风险。
缺点
- 产品的组成部分必须相同,这限制了其使用范围。
- 如果产品的内部变化复杂,该模式会增加很多的建造者类。
建造者模式的本质
建造者模式的本质:分离整体构建算法和部件构造
构建一个复杂的对象,本来就有构造的过程,以及构建过程中具体的实现。建造者模式就是用来分离这两个部分,从而使得程序结构更松散,扩展更容易,复用性更好,同时也会使得代码更清晰,意图更明确。
虽然在建造者模式的整体构建算法中,会一步一步引导Builder来构建对象,但这并不是说其主要就是用来实现分不构建对象的。该模式的重心还是在于分离整体构建算法和部件构造,而分步骤构建对象不过是整体构建算法的一个简单表现,或者说是一个附带产物。
使用场景
- 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
- 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。
模式的扩展
建造者(Builder)模式在应用过程中可以根据需要改变,如果创建的产品种类只有一种,只需要一个具体建造者,这时可以省略掉抽象建造者,甚至可以省略掉指挥者角色。
工厂模式总结
原则:
-
解耦:把对象的创建和使用的过程分开。
-
工厂负责对象的创建,包括其init方法的调用,黑盒创建过程。
-
面向接口编程: 使用者只管使用,只知其接口而不知其实现类。
对比:
-
静态工厂:把所有对象的创建逻辑集中到一个(专业)类里处理。
-
工厂方法模式:一个工厂负责创建一个产品类的创建。
-
抽象工厂模式:将一个系列的产品的工厂合并成一个工厂,负责生产这个系列的产品。
-
建造者模式:对象的创建比较复杂时,按步骤一块块创建,让创建过程模板化。