本文转载自微信公众号「JavaKeeper」,作者海星。转载本文请联系JavaKeeper公众号。
创新互联专业提供多线BGP机房服务,为用户提供五星数据中心、电信、双线接入解决方案,用户可自行在线购买多线BGP机房服务,并享受7*24小时金牌售后服务。
Builder Pattern,中文翻译为建造者模式或者构建者模式,也有人叫它生成器模式。
建造者模式是一种创建型设计模式, 使你能够分步骤创建复杂对象。它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
程序员麽,先上个 hello world 热热身
- public class User {
- private Long id;
- private String name;
- private Integer age; //可选
- private String desc; //可选
- private User(Builder builder) {
- this.id = builder.id;
- this.name = builder.name;
- this.age = builder.age;
- this.desc = builder.desc;
- }
- public static Builder newBuilder(Long id, String name) {
- return new Builder(id, name);
- }
- public Long getId() {return id;}
- public String getName() {return name;}
- public Integer getAge() {return age;}
- public String getDesc() {return desc;}
- @Override
- public String toString() {
- return "Builder{" +
- "id=" + id +
- ", name='" + name + '\'' +
- ", age=" + age +
- ", desc='" + desc + '\'' +
- '}';
- }
- public static class Builder {
- private Long id;
- private String name;
- private Integer age;
- private String desc;
- private Builder(Long id, String name) {
- Assert.assertNotNull("标识不能为空",id);
- Assert.assertNotNull("名称不能为空",name);
- this.id = id;
- this.name = name;
- }
- public Builder age(Integer age) {
- this.age = age;
- return this;
- }
- public Builder desc(String desc) {
- this.desc = desc;
- return this;
- }
- public User build() {
- return new User(this);
- }
- }
- public static void main(String[] args) {
- User user = User.newBuilder(1L, "starfish").age(22).desc("test").build();
- System.out.println(user.toString());
- }
- }
这样的代码有什么优缺点呢?
主要优点:
主要缺点:
当然,以上代码,就可以通过 Lombok 的 @Builder 简化代码
如果我们就那么三三两两个参数,直接构造函数配合 set 方法就能搞定的,就不用套所谓的模式了。
高射炮打蚊子——不合算
假设有这样一个复杂对象, 在对其进行构造时需要对诸多成员变量和嵌套对象进行繁复的初始化工作。这些初始化代码通常深藏于一个包含众多参数且让人基本看不懂的构造函数中;甚至还有更糟糕的情况, 那就是这些代码散落在客户端代码的多个位置。
这时候才是构造器模式上场的时候
上边的例子,其实属于简化版的建造者模式,只是为了方便构建类中的各个参数,”正经“的和这个有点差别,更倾向于用同样的构建过程分步创建不同的产品类。
我们接着扯~
从 UML 图上可以看到有 4 个不同的角色
假设我是个汽车工厂,需求就是能造各种车(或者造电脑、造房子、做煎饼、生成不同文件TextBuilder、HTMLBuilder等等,都是一个道理)
1、生成器(Builder)接口声明在所有类型生成器中通用的产品构造步骤
- public interface CarBuilder {
- void setCarType(CarType type);
- void setSeats(int seats);
- void setEngine(Engine engine);
- void setGPS(GPS gps);
- }
2、具体的生成器(Concrete Builders)提供构造过程的不同实现
- public class SportsCarBuilder implements CarBuilder {
- private CarType carType;
- private int seats;
- private Engine engine;
- private GPS gps;
- @Override
- public void setCarType(CarType type) {
- this.carType = type;
- }
- @Override
- public void setSeats(int seats) {
- this.seats = seats;
- }
- @Override
- public void setEngine(Engine engine) {
- this.engine = engine;
- }
- @Override
- public void setGPS(GPS gps) {
- this.gps = gps;
- }
- public Car getResult() {
- return new Car(carType, seats, engine, gps);
- }
- }
3、产品(Products)是最终生成的对象
- @Setter
- @Getter
- @ToString
- public class Car {
- private final CarType carType;
- private final int seats;
- private final Engine engine;
- private final GPS gps;
- private double fuel;
- public Car(CarType carType,int seats,Engine engine,GPS gps){
- this.carType = carType;
- this.seats = seats;
- this.engine = engine;
- this.gps = gps;
- }
- }
4、主管(Director)类定义调用构造步骤的顺序,这样就可以创建和复用特定的产品配置(Director 类的构造函数的参数是 CarBuilder,但实际上没有实例传递出去作参数,因为 CarBuilder 是接口或抽象类,无法产生对象实例,实际传递的是 Builder 的子类,根据子类类型,决定生产内容)
- public class Director {
- public void constructSportsCar(CarBuilder builder){
- builder.setCarType(CarType.SPORTS_CAR);
- builder.setSeats(2);
- builder.setEngine(new Engine(2.0,0));
- builder.setGPS(new GPS());
- }
- public void constructCityCar(CarBuilder builder){
- builder.setCarType(CarType.CITY_CAR);
- builder.setSeats(4);
- builder.setEngine(new Engine(1.5,0));
- builder.setGPS(new GPS());
- }
- public void constructSUVCar(CarBuilder builder){
- builder.setCarType(CarType.SUV);
- builder.setSeats(4);
- builder.setEngine(new Engine(2.5,0));
- builder.setGPS(new GPS());
- }
- }
5、客户端使用(最终结果从建造者对象中获取,主管并不知道最终产品的类型)
- public class Client {
- public static void main(String[] args) {
- Director director = new Director();
- SportsCarBuilder builder = new SportsCarBuilder();
- director.constructSportsCar(builder);
- Car car = builder.getResult();
- System.out.println(car.toString());
- }
- }
适用场景其实才是理解设计模式最重要的,只要知道这个业务场景需要什么模式,网上浪~程序员能不会吗
假设你的构造函数中有 N 个可选参数,那 new 各种实例的时候就很麻烦,需要重载构造函数多次
如果你需要创建的各种形式的产品, 它们的制造过程相似且仅有细节上的差异, 此时可使用建造者模式。
建造者模式让你能分步骤构造产品。你可以延迟执行某些步骤而不会影响最终产品。你甚至可以递归调用这些步骤, 这在创建对象树时非常方便。
抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式不需要关心抽象过程,只关心什么产品由什么工厂生产即可。而建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而生产一个新的产品。
设计模式,这玩意看简单的例子,肯定能看得懂,主要是结合自己的业务思考怎么应用,让系统设计更完善,懂了每种模式后,可以找找各种框架源码或在 github 搜搜相关内容,看看实际中是怎么应用的。
refactoringguru.cn
网页名称:建造者模式——不止提高代码档次
网页网址:http://www.shufengxianlan.com/qtweb/news29/143779.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联