java设计模式之建造者模式

前言

建造者模式(Builder Pattern):

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。(Separate the construction of a complex object from its representation so that the same construction process can create different representations.)

建造模式的本质:

  • List item分离了对象子组件的单独构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于:某个对象的构建过程复杂的情况下使用。
  • 由于实现了构建和装配的解耦。不同的构建器,相同的装配,也可以做出不同的对象;相同的构建器,不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配算法的解耦,实现了更好的复用。
  • 建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。

应用场景:

  • java中的StringBuilder类的append方法;
  • SQL中的PreparedStatement;
  • JDOM中,DomBuilder、SAXBuilder;
  • 去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐";
  • 一个对象有非常复杂的内部结构,想把复杂对象的创建和使用分离

建造者模式的优缺点:

优点:

  • 封装性好,创建和使用分离;无需修改原有代码,符合“开闭原则”。
  • 拓展性好,建造类之间独立,一定程度上解耦;代码解耦,模块化,方便维护。产品本身与创建过程解耦,可以使用相同的创建过程得到不同的产品。

缺点:

  • 产品必须有共同点,使用范围有限。建造者模式创造出来的产品,其组成部分基本相同。如果产品之间的差异较大,则不适用这个模式。
  • 若产品内部发生变化,建造者都要修改,成本较大;若内部变化复杂,会有很多的建造类。 # 与工厂模式的区别是 建造者模式更加关注与零件装配的顺序。

Mybatis中用到的建造者模式:

SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder等。
比如:XMLConfigBuilder读取配置文件构建出Configuration对象,然后SqlSessionFactoryBuilder使用Configuration对象作为参数,构建出SqlSessionFactory对象。
原因:这么做的原因是Mybatis的初始化工作较复杂,不是一个构造函数就能包括的。所以采用了分层构建方法。例如Mybatis中极其重要的Configuration对象,它庞大且复杂,初始化比较麻烦,所以使用专门的建造者XMLConfigBuilder进行构建。

实例:

比如:建造者模式可以用于描述KFC如何创建套餐:套餐是一个复杂对象,它一般包含主食(如汉堡、鸡肉卷等)和饮料(如果汁、可乐等)等组成部分,不同的套餐有不同的组成部分,而KFC的服务员可以根据顾客的要求,一步一步装配这些组成部分,构造一份完整的套餐,然后返回给顾客。

类图如下:
在这里插入图片描述

编码步骤以及JAVA代码

整个过程大致可以分为5步
第一,定义Product(产品角色): 一个具体的产品对象。


/**
 * 一个具体产品,实体
 */
public class Meal {
    private String food;
    private String drink;

    public String getFood() {
        return food;
    }

    public void setFood(String food) {
        this.food = food;
    }

    public String getDrink() {
        return drink;
    }

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

第二,定义Builder(抽象建造者): 创建一个Product对象的各个部件指定的抽象接口。


/**
 * 抽象建造者
 * 创建一个Product对象的各个部件指定的抽象接口
 */
public abstract class MealBuilder {
    Meal meal= new Meal();
    public abstract void buildFood();
    public abstract void buildDrink();
    public Meal getMeal(){
        return meal;
    }
}

第三,定义ConcreteBuilder(具体建造者): 实现抽象接口,构建和装配各个部件。

/**
 * 具体建造者 A
 * 实现抽象接口,构建和装配各个部件
 */
public class MealA extends MealBuilder {
    @Override
    public void buildFood() {
        meal.setFood("汉堡");
    }

    @Override
    public void buildDrink() {
        meal.setDrink("可乐");
    }
}
/**
 * 具体建造者 B
 */
public class MealB extends MealBuilder {
    @Override
    public void buildFood() {
        meal.setFood("鸡翅");
    }

    @Override
    public void buildDrink() {
        meal.setDrink("养乐多");
    }
}

第四,定义Director(指挥者): 构建一个使用Builder接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。

/**
 * 定义指挥者
 * 构建一个使用Builder接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用,
 * 一是:隔离了客户与对象的生产过程,
 * 二是:负责控制产品对象的生产过程。
 */
public class KFCWaiter {
    private MealBuilder mealBuilder;

    public KFCWaiter(MealBuilder mealBuilder) {
        this.mealBuilder = mealBuilder;
    }
    public Meal construct(){
        // 准备食物
        mealBuilder.buildFood();
        // 装备饮料
        mealBuilder.buildDrink();
        return mealBuilder.getMeal();
    }
}

第五,定义测试类:

public class Test {
    public static void main(String[] args) {
        // A套餐
        MealA mealA = new MealA();
        KFCWaiter kfcWaiter1 = new KFCWaiter(mealA);
        // 得到A套餐的具体食物
        Meal meal_A = kfcWaiter1.construct();
        System.out.print("套餐A的组成部分:");
        System.out.println("食物:"+meal_A.getFood()+";   "+"饮品:"+meal_A.getDrink());
        MealB mealB = new MealB();
        KFCWaiter kfcWaiter2 = new KFCWaiter(mealB);
        // 得到B套餐的具体食物
        Meal meal_B = kfcWaiter2.construct();
        System.out.print("套餐B的组成部分:");
        System.out.println("食物:"+meal_B.getFood()+";   "+"饮品:"+meal_B.getDrink());
    }
}

测试结果如下图所示:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值