建造者模式

本文深入解析建造者模式的定义、作用及其实现过程,通过游玩方案的实例,展示了如何将复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

建造者模式(Builder Pattern)

定义

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

只把复杂对象(产品product)定义出来,定义它需要的各种属性,但属性的赋值交给另一个对象(builder),且在builder内决定赋值顺序,并把产品返回(个人理解)

模式总结过程
  1. 有一个村子,风景秀丽,而你是村长,有一天,一个人来找你,叫你帮给他出一个游玩的方案
public class Scheme {

    // 游玩时间
    private String time;

    // 住哪
    private String hetol;

    // 特色美食
    private List<String> foodList;

    // 游玩项目
    private List<String> playList;

    // getters、setters and toString
}

public class Client {

    public static void main(String[] args) {
        Scheme scheme = new Scheme();
        scheme.setTime("一天");
        scheme.setHetol("不需要");
        scheme.setFoodList(Arrays.asList("红烧茄子", "家常豆腐"));
        scheme.setPlayList(Arrays.asList("百年老屋", "青山绿水"));
        System.out.println(scheme);
    }
}
/*
方案:《游玩时间》:一天, 《住宿》:不需要, 《特色美食》:[红烧茄子, 家常豆腐], 《游玩项目》:[百年老屋, 青山绿水]
*/
  1. 几天后,又来了一个人,他需要的方案也一样,你又需要重复做上一个方案
public class Client {

    public static void main(String[] args) {
        Scheme scheme = new Scheme();
        scheme.setTime("一天");
        scheme.setHetol("不需要");
        scheme.setFoodList(Arrays.asList("红烧茄子", "家常豆腐"));
        scheme.setPlayList(Arrays.asList("百年老屋", "青山绿水"));
        System.out.println(scheme);
    }
}
  1. 这样,每来一个人,你都需要重复做重复的事情,所以,你把重复的事情抽出来
// 在Scheme类中,加构造方法
public Scheme() {
    this.time = "一天";
    this.hetol = "不需要";
    this.foodList = Arrays.asList("红烧茄子", "家常豆腐");
    this.playList = Arrays.asList("百年老屋", "青山绿水");
}

// 这样,就轻松多了
public class Client {

    public static void main(String[] args) {
        Scheme scheme = new Scheme();
        System.out.println(scheme);
    }
}
/*
方案:《游玩时间》:一天, 《住宿》:不需要, 《特色美食》:[红烧茄子, 家常豆腐], 《游玩项目》:[百年老屋, 青山绿水]
*/
  1. 但是,不是每一个的需求是完全一样的,有些人需要住宿,有些人只想游玩(自带食物),所以,得把设值代码再抽取出来,相当于制作好几个模板,客户需要什么就打印什么(也就是说,提供几套现成的方案,让客户去选择)
// 产品
public class Scheme {

    // 游玩时间
    private String time;

    // 住哪
    private String hetol;

    // 特色美食
    private List<String> foodList;

    // 游玩项目
    private List<String> playList;
}

// 抽象建造者
public abstract class Builder {

    protected Scheme scheme = new Scheme();

    public abstract void buildTime();

    public abstract void buildHotel();

    public abstract void buildFoodList();

    public abstract void buildPlayList();

    public Scheme getResult() {
        buildTime();
        buildHotel();
        buildFoodList();
        buildPlayList();
        return scheme;
    }
}

// 具体建造者A
public class SchemeBuilderA extends Builder {
    @Override
    public void buildTime() {
        scheme.setTime("一天");
    }

    @Override
    public void buildHotel() {
        scheme.setHetol("不需要");
    }

    @Override
    public void buildFoodList() {
        scheme.setFoodList(Arrays.asList("红烧茄子", "家常豆腐"));
    }

    @Override
    public void buildPlayList() {
        scheme.setPlayList(Arrays.asList("百年老屋", "青山绿水"));
    }
}

// 具体建造者B
public class SchemeBuilderB extends Builder {
    @Override
    public void buildTime() {
        scheme.setTime("三天");
    }

    @Override
    public void buildHotel() {
        scheme.setHetol("农民房");
    }

    @Override
    public void buildFoodList() {
        scheme.setFoodList(Arrays.asList("走地鸡", "自养鸭"));
    }

    @Override
    public void buildPlayList() {
        scheme.setPlayList(Arrays.asList("百年老屋", "民族舞"));
    }
}

// 客户端
public class Client {

    public static void main(String[] args) {
        Scheme scheme1 = new SchemeBuilderA().getResult();
        Scheme scheme2 = new SchemeBuilderB().getResult();
        System.out.println(scheme1);
        System.out.println(scheme2);
    }
}
/*
方案:《游玩时间》:一天, 《住宿》:不需要, 《特色美食》:[红烧茄子, 家常豆腐], 《游玩项目》:[百年老屋, 青山绿水]
方案:《游玩时间》:三天, 《住宿》:农民房, 《特色美食》:[走地鸡, 自养鸭], 《游玩项目》:[百年老屋, 民族舞]
*/

这样,每有不同种类的需求,就增加一个具体建造者类即可

  1. 到这里,在我的理解中,建造者模式就完了,没有drector指导者这个角色,我觉得这是多此一举的。指导者只是把赋值过程抽象到一个新类中,完全没必要,如果建造过程有不一样的,那就与模式的定义不符合了

定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。是指同样的构建过程得到不同的表示,这里强调的是同样的构建过程!

// 指导者做的工作,顺序调用具体构建者的方法,完全可以放在抽象类中完成
buildTime();
buildHotel();
buildFoodList();
buildPlayList();
  1. 就算有不同的构建过程,也可以在抽象建造者与具体建造者中再加一层抽象,中间抽象层定义不同的建造过程,具体建造者再继承中间抽象层即可
角色
  1. 产品(product):客户端需要的对象,这个对象只声明自己有哪些属性即可(这里不讨论方法)

比如,定义机器人对象,只需要声明它有头、身、手、脚等属性即可,至于需要什么样的手,什么样的头,则交给concreteBuilder

  1. 建造者(builder):提供统一的规范,赋值方法与产品属性一一对应,并提供一个方法,这个方法返回赋值完成后的产品对象

比如,生产一个机器人,则必须给它一个规范,这个规范就是建造头、身、手、脚等,每一个具体建造者,都必须按照自己的需求去生产这些部件

  1. 具体建造者(concreteBuilder):提供具体的赋值操作,不同产品需要不同的具体建造者

有生活机器人,工作机器人,学习机器人等,不同的机器人对不同部件的要求不同

  1. 指导者(director):控制部件的组装过程,调用不同的具体建造者生产不同的对象

其实就是调用各个属性的赋值方法,如果放在具体建造者类中,则每个具体建造者类都有一份重复的,所以就把这个调用过程抽取出来,成为指导者类,也是为了统一建造过程(我这里是抽取到抽象建造者中,这也是我觉得director没卵用的原因)

与工厂方法的区别
  1. “建造者”相当于工厂方法中的“工厂”,“具体建造者”相当于工厂方法中的“具体工厂”,但是,工厂方法中的“产品类”与“具体工厂”是一一对应的,多一种产品就得多个一个产品类和一具体工厂,而建造者模式是一个“产品类”对应多个“具体建造者”,多一种产品,只需要多一个具体建造者即可
  2. 工厂方法针对的是产品,建造者模式针对的是产品的部件
  3. 对象内容,工厂方法是由对象本身决定的,而建造者模式是由具体建造者(concreteBuilder)决定的,与对象分离
  4. 工厂方法得到的对象属于不同的类(虽然这些类有共同的接口),而建造者模式得到的对象属于同一个类(不一定实现接口)
  5. 工厂方法注重得到同一接口下不同的对象,建造者模式注重得到同一个类下不同的对象表示
优点
  1. 解耦:创建和使用分离
  2. 扩展性好:加一类产品,只需要加一个具体建造者类,符合开闭原则
  3. 客户端只需要指定产品的类型,就可以得到对应的对象,而不需要关注具体的创建过程
缺点
  1. 产品内部属性发生改变时,所有建造者都要修改,成本较大
应用
  1. 所需要的对象比较复杂,且有不同种类时,如车是复杂对象,车又分油车、电车、混动车等,这些车的部件都是不同的,但是都是同样的构建过程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值