建造者模式(学习笔记2021.09.16)

建造者模式(学习笔记2021.09.16)

前言:

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

**意图:**将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

**主要解决:**主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

**何时使用:**一些基本部件不会变,而其组合经常变化的时候。

**如何解决:**将变与不变分离开。

**关键代码:**建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。

应用实例: 1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。 2、JAVA 中的 StringBuilder。

优点: 1、建造者独立,易扩展。 2、便于控制细节风险。

缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。

使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。

**注意事项:**与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。

当一个类的构造函数参数个数超过4-5个,而且这些参数有些是可选的参数,考虑使用构造者模式。

前提条件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mghTiJXV-1631791721441)(https://z3.ax1x.com/2021/09/16/4mzyDK.md.png)]

从上面可以看出, 假期这个javaBean 有很多的参数, 并且有很多参数, 有的参数是必选的, 比如: 天数、旅馆、公园门票, 而又存在一些非必选的参数, 比如: 用餐、特殊活动、

通常我们之前使用的解决方案是, 在javaBean中创建多个有参构造方法或者使用set方法,

第一方案主要是使用及阅读不方便。你可以想象一下,当你要调用一个类的构造函数时,你首先要决定使用哪一个,然后里面又是一堆参数,如果这些参数的类型很多又都一样,你还要搞清楚这些参数的含义,很容易就传混了。

第二方案在构建过程中对象的状态容易发生变化,造成错误。因为那个类中的属性是分步设置的,所以就容易出错

为了解决这些痛点,builder模式就横空出世了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GrfPp1tt-1631791721443)(https://z3.ax1x.com/2021/09/16/4nCXwV.md.png)]

使用建造者模式解决上面前提问题

简单模式的构造者

/**
 * @Author: ZhiHao
 * @Date: 2021/9/16 16:54
 * @Description: 简单的建造者模式
 * @Versions 1.0
 **/
@ToString
public class Vacation {

    private Integer day; // 天数, 必选
    private String hotel; // 旅馆, 必选
    private String parkTickets; // 公园门票, 必选
    private HaveMeals haveMeals; // 吃饭, 可选
    private Activity activity; // 活动, 可选

    public Vacation(SimpleBuilder simpleBuilder) {
        this.day = simpleBuilder.day;
        this.hotel = simpleBuilder.hotel;
        this.parkTickets = simpleBuilder.parkTickets;
        this.haveMeals = simpleBuilder.haveMeals;
        this.activity = simpleBuilder.activity;
    }

    // 内置静态简单生成器SimpleBuilder
    public static class SimpleBuilder {
        private Integer day; // 天数, 必选
        private String hotel; // 旅馆, 必选
        private String parkTickets; // 公园门票, 必选
        private HaveMeals haveMeals; // 吃饭, 可选
        private Activity activity; // 活动, 可选

        public SimpleBuilder(Integer day, String hotel, String parkTickets) {
            this.day = day;
            this.hotel = hotel;
            this.parkTickets = parkTickets;
        }

        // 可选的选择性设置
        public SimpleBuilder setHaveMeals(HaveMeals haveMeals) {
            this.haveMeals = haveMeals;
            return this;
        }
        public SimpleBuilder setActivity(Activity activity) {
            this.activity = activity;
            return this;
        }
        // 最终建造出需要假期对象
        public Vacation getVacation() {
            return new Vacation(this);
        }
    }
}
活动与用餐类
@Data
public class Activity {
    private String ActivityType;
    public Activity(String activityType) {
        ActivityType = activityType;
    }
}
//-----------------------------------------------------------
@Data
public class HaveMeals {
    private String restaurant;
    public HaveMeals(String restaurant) {
        this.restaurant = restaurant;
    }
}
测试:
public void applicationTest() throws Exception {
        Vacation.SimpleBuilder simpleBuilder = new Vacation.SimpleBuilder(1,"我的旅馆","100块的门票");
        System.out.println(simpleBuilder.getVacation());
        Vacation.SimpleBuilder simpleBuilder2 = new Vacation.SimpleBuilder(2,"国内旅馆","200块的门票");
        Vacation vacation2 = simpleBuilder2.setHaveMeals(new HaveMeals("海鲜餐厅"))
                .setActivity(new Activity("冰上模式"))
                .getVacation();
        System.out.println(vacation2);
        Vacation.SimpleBuilder simpleBuilder3 = new Vacation.SimpleBuilder(3,"公园旅馆","230块的门票");
        Vacation vacation3 = simpleBuilder3.setHaveMeals(new HaveMeals("自助餐厅"))
                .setActivity(new Activity("末世竞技场"))
                .getVacation();
        System.out.println(vacation3);
    }
// --------------------------------
Vacation(day=1, hotel=我的旅馆, parkTickets=100块的门票, haveMeals=null, activity=null)
Vacation(day=2, hotel=国内旅馆, parkTickets=200块的门票, haveMeals=HaveMeals(restaurant=海鲜餐厅), activity=Activity(ActivityType=冰上模式))
Vacation(day=3, hotel=公园旅馆, parkTickets=230块的门票, haveMeals=HaveMeals(restaurant=自助餐厅), activity=Activity(ActivityType=末世竞技场))

传统Builder模式

传统builder模式有4个角色。

  • Product: 最终要生成的对象,例如 Vacation 实例。
  • Builder: 构建者的抽象基类(有时会使用接口代替)。其定义了构建Product的抽象步骤,其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法Product getProduct()
  • ConcreteBuilder: Builder的实现类。
  • Director: 决定如何构建最终产品的算法. 其会包含一个负责组装的方法void Construct(Builder builder), 在这个方法中通过调用builder的方法,就可以设置builder,等设置完成后,就可以通过builder的 getProduct() 方法获得最终的产品。
最终要生成的对象(角色)

我们最终需要生成的Vacation对象, 已经有了

@ToString
@Data
public class Vacation {

    private Integer day; // 天数, 必选
    private String hotel; // 旅馆, 必选
    private String parkTickets; // 公园门票, 必选
    private HaveMeals haveMeals; // 吃饭, 可选
    private Activity activity; // 活动, 可选

    public Vacation(Integer day, String hotel, String parkTickets) {
        this.day = day;
        this.hotel = hotel;
        this.parkTickets = parkTickets;
    }
}
创建构建者的抽象基类(角色)
public abstract class VacationBuilder {
    // 添加餐厅
    public abstract VacationBuilder addHaveMeals();
    // 添加活动
    public abstract VacationBuilder addActivity();
    // 获取假期对象
    public abstract Vacation getVacation();
}
构建者的实现类(角色)
/**
 * @Author: ZhiHao
 * @Date: 2021/9/16 18:43
 * @Description: 构造第一天假期实现类
 * @Versions 1.0
 **/
public class OneDayVacationBuilderImpl extends VacationBuilder {

    private Vacation vacation;

    public OneDayVacationBuilderImpl(Integer day,
                                     String hotel,
                                     String parkTickets) {
        this.vacation = new Vacation(day,hotel,parkTickets);
    }

    @Override
    public VacationBuilder addHaveMeals() {
        return this;
    }

    @Override
    public VacationBuilder addActivity() {
        return this;
    }

    @Override
    public Vacation getVacation() {
        return vacation;
    }
}
// -----------------------------第二天假期----------------------------------
/**
 * @Author: ZhiHao
 * @Date: 2021/9/16 18:43
 * @Description: 构造第二天假期实现类
 * @Versions 1.0
 **/
public class TwoDayVacationBuilderImpl extends VacationBuilder {

    private Vacation vacation;

    public TwoDayVacationBuilderImpl(Integer day,
                                     String hotel,
                                     String parkTickets) {
        this.vacation = new Vacation(day,hotel,parkTickets);
    }

    @Override
    public VacationBuilder addHaveMeals() {
        vacation.setHaveMeals(new HaveMeals("海鲜餐厅"));
        return this;
    }

    @Override
    public VacationBuilder addActivity() {
        vacation.setActivity(new Activity("冰上模式"));
        return this;
    }

    @Override
    public Vacation getVacation() {
        return vacation;
    }
}
指挥者 (角色)

构建的算法调用者, 调用构造者, 进行构造并最终获取到构造出来的对象。

/**
 * @Author: ZhiHao
 * @Date: 2021/9/16 18:52
 * @Description: 指挥者, 负责调用建造者,  都是单一职责
 * @Versions 1.0
 **/
public class VacationDirector {

    private VacationBuilder vacationBuilder;

    public VacationDirector(VacationBuilder vacationBuilder) {
        this.vacationBuilder = vacationBuilder;
    }

    // 进行建造
    public Vacation ConstructVacation() {
        return vacationBuilder.addActivity()
                .addHaveMeals()
                .getVacation();
    }
}
测试
public void applicationTest() throws Exception {
        VacationBuilder vacationBuilder = new OneDayVacationBuilderImpl(1,"我的旅馆","100块的门票");
        VacationDirector vacationDirector = new VacationDirector(vacationBuilder);
        System.out.println(vacationDirector.constructVacation());

        VacationBuilder vacationBuilder2 = new TwoDayVacationBuilderImpl(2,"旅馆","50块的门票");
        VacationDirector vacationDirector2 = new VacationDirector(vacationBuilder2);
        System.out.println(vacationDirector2.constructVacation());
    }
// ----------------------------------------------
Vacation(day=1, hotel=我的旅馆, parkTickets=100块的门票, haveMeals=null, activity=null)
Vacation(day=2, hotel=旅馆, parkTickets=50块的门票, haveMeals=HaveMeals(restaurant=海鲜餐厅), activity=Activity(ActivityType=冰上模式))

最后如果不遵守单一职责的时候, 可以把指挥者 (角色) 放到建造者抽象基类中

public abstract class VacationBuilder {

    // 添加餐厅
    public abstract VacationBuilder addHaveMeals();
    // .......
    public Vacation constructVacation(VacationBuilder vacationBuilder) {
        return vacationBuilder.addActivity()
                .addHaveMeals()
                .getVacation();
    }
}

1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

懵懵懂懂程序员

如果节省了你的时间, 请鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值