建造者模式-入门

本文介绍了建造者模式,一种解决复杂对象构造问题的设计模式。当构造器参数超过四个时,推荐使用建造者模式。文章详细阐述了建造者模式的角色、实现方式、简化实现以及Lombok的@Builder注解,并讨论了其优缺点和适用场景。
摘要由CSDN通过智能技术生成

问题

最近在做项目时,经常遇到包含上十个属性的实体类,主要出现以下问题

  • 创建类的对象时,需要传入许多参数,或使用大量的set方法,代码极其臃肿,可读性差;
  • 其他人阅读代码时,难以快速理解其中的属性,增加学习成本;

最终,给我启发的是以下这段规则:

当构造器参数超过四个时,建议使用建造者模式

下面我们来看一下基础的建造者模式是怎样的,并一步步解决上面提到的问题;

引入场景

建造者模式,简而言之,就是一个复杂对象的构造和表示分离,用于应对内部数据、结构复杂的类(通常是持有数据的类,如VO、Config、PO、Entity等);

假设有这样一个场景,你需要建造两类房子-普通房子和别墅,那么与之对应的有两种解决方案:

  • 你已知建造方法,自己建造两类房子;
  • 你不知道建造方法,将建造的权利交给已知建造方法的人,让他来建造两类房子;

普通解法

目前已知建造方法,自己建造两类房子,将现实场景转化为类图

普通解法的实现

// AbstractHouse.java
public abstract class AbstractHouse{
    abstact void buildBasic();
    abstact void buildWall();
    abstact void buildRoof();
    public void build();
}

// CommonHouse.java
public class CommonHouse extends AbstractHouse{
    @Override
    void buildBasic() {
        System.out.println("Common House build Basic");
    }

    @Override
    void buildWall() {
        System.out.println("Common House build Wall");
    }

    @Override
    void buildRoof() {
        System.out.println("Common House build roof");
    }
}

// HighBuilding.java
public class CommonHouse extends AbstractHouse{
    @Override
    void buildBasic() {
        System.out.println("High Building build Basic");
    }

    @Override
    void buildWall() {
        System.out.println("High Building build Wall");
    }

    @Override
    void buildRoof() {
        System.out.println("High Building build roof");
    }
}

以上为房子的抽象类和两个实现类,客户建房子的过程如下

// Client.java
public class Client {
    public static void main(String[] args) {
        // build common house
        CommonHouse commonHouse = new CommonHouse();
        commonHouse.build();
        // build high building
        HighBuilding highBuilding=new HighBuilding();
        highBuilding.build();
    }
}

分析:可以看到Client中客户需要自己调用build方法去执行建造房子的过程,相当于建房子的过程是暴露给客户端的,违背了开闭原则。

建造者模式

建造者将复杂对象的构造过程抽象出来,使得这个对象可以通过不同的构造过程构造出不同属性的对象,它使得用户只需知道复杂对象的内容和类型就可以构造它们,而无须知晓内部的构造细节,建造者有四个角色:

  • Product:角色;
  • Builder:抽象构造者,创建一个产品对象的各个部件指定的接口/抽象;
  • ConcreteBuilder:Builder的实现,实现接口,构建和装配各个部件;
  • Director:指挥者,构建一个使用Builder接口的对象,主要是用于创建一个复杂对象,有两个作用:
    • 隔离客户和生产对象的过程;
    • 负责控制生产产品的过程;

类图如下:

在建房子的场景中,具体类图如下:

实现代码如下:

// House.java(相当于Product)
public class House {
    private String basic;
    private String wall;
    private String roof;
	// 省略set、get方法
}

// HouseBuilder.java(相当于Builder)
public abstract class HouseBuilder {
    private House house=new House();

    abstract void buildBasic();
    abstract void buildWall();
    abstract void buildRoof();

    public House build(){
        return house;
    }
}

// CommonHouse.java(相当于ConcreteBuilder)
public class CommonHouse extends HouseBuilder{
    @Override
    void buildBasic() {
        System.out.println("Common house build basic");
    }

    @Override
    void buildWall() {
        System.out.println("Common house build wall");
    }

    @Override
    void buildRoof() {
        System.out.println("Common house build roof");
    }
}

// HighBuilder.java(相当于ConcreteBuilder)
public class CommonHouse extends HouseBuilder{
    @Override
    void buildBasic() {
        System.out.println("High Building build basic");
    }

    @Override
    void buildWall() {
        System.out.println("High Building build wall");
    }

    @Override
    void buildRoof() {
        System.out.println("High Building build roof");
    }
}

// HouseDirector.java(相当于Director)
public class HouseDirector {
    private HouseBuilder houseBuilder = null;

    // 构造器传入HouseBuilder
    public HouseDirector(HouseBuilder houseBuilder) {
        this.houseBuilder = houseBuilder;
    }

    public void setHouseBuilder(HouseBuilder houseBuilder) {
        this.houseBuilder = houseBuilder;
    }

    // 指挥具体建造流程
    public House construct(){
        houseBuilder.buildBasic();
        houseBuilder.buildWall();
        houseBuilder.buildRoof();
        return houseBuilder.build();
    }
}

客户端调用如下

// Client.java
public class Client {
    public static void main(String[] args) {
        // 建造CommonHouse
        CommonHouse commonHouse = new CommonHouse();
        HouseDirector houseDirector = new HouseDirector(commonHouse);
        houseDirector.construct();
        // 建造HighBuilding
        HighBuilding highBuilding = new HighBuilding();
        HouseDirector houseDirector2 = new HouseDirector(highBuilding);
        houseDirector2.construct();
    }
}

分析:可以看到,通过director这一角色,将建房子的过程与客户端隔离开来,使得用户只需关心需要建造的房子的类型,而无须关注建房子的过程;

简化实现

现在我们回到文章开头的准则:构造器参数超过四个,使用建造者模式,问题是,如何使用?下面给出一段示例代码

// NewComputer.java
public class NewComputer {
    private String cpu;
    private String screen;
    private String memory;
    private String mainboard;

    // 禁止调用构造器
    public NewComputer() {
        throw new RuntimeException("cannot init!");
    }

    private NewComputer(Builder builder) {
        cpu = builder.cpu;
        screen = builder.screen;
        memory = builder.memory;
        mainboard = builder.mainboard;
    }

    public static final class Builder {
        private String cpu;
        private String screen;
        private String memory;
        private String mainboard;

        public Builder() {
        }

        public Builder cpu(String val) {
            this.cpu = val;
            return this;
        }

        public Builder screen(String val) {
            this.screen = val;
            return this;
        }

        public Builder memory(String val) {
            this.memory = val;
            return this;
        }

        public Builder mainboard(String val) {
            this.mainboard = val;
            return this;
        }

        public NewComputer build(){
            return new NewComputer(this);
        }
    }
}

// Client.java
public class Client {
    public static void main(String[] args) {
        // 建造者模式
        NewComputer newComputer = new NewComputer.Builder()
                .cpu("new cpu")
                .screen("new  screen")
                .memory("new memory")
                .mainboard("new mainboard")
                .build();
    }
}

上述代码相当于对建造者模式的简化,NewComputer(产品)内部定义了一个静态内部类Builder(ConcreteBuilder),即省去了建造者模式中的Director、Builder,使得产品与创建过程之间的联系更加紧密,简化了建造者模式,同时客户端仍然只能通过产品内部的Builder生产产品,也达到了隔离用户与产品生产过程的目的;

Lombok的@Builder注解

lombok中可以使用@Builder实现构造者模式,示例如下

// NewComputer.java
@Builder
public class NewComputer {
    private String cpu;
    private String screen;
    private String memory;
    private String mainboard;
}

编译以后的.class文件如下

// NewComputer.class
public class NewComputer {
    private String cpu;
    private String screen;
    private String memory;
    private String mainboard;

    NewComputer(final String cpu, final String screen, final String memory, final String mainboard) {
        this.cpu = cpu;
        this.screen = screen;
        this.memory = memory;
        this.mainboard = mainboard;
    }

    public static NewComputer.NewComputerBuilder builder() {
        return new NewComputer.NewComputerBuilder();
    }

    public static class NewComputerBuilder {
        private String cpu;
        private String screen;
        private String memory;
        private String mainboard;

        NewComputerBuilder() {
        }

        public NewComputer.NewComputerBuilder cpu(final String cpu) {
            this.cpu = cpu;
            return this;
        }

        public NewComputer.NewComputerBuilder screen(final String screen) {
            this.screen = screen;
            return this;
        }

        public NewComputer.NewComputerBuilder memory(final String memory) {
            this.memory = memory;
            return this;
        }

        public NewComputer.NewComputerBuilder mainboard(final String mainboard) {
            this.mainboard = mainboard;
            return this;
        }

        public NewComputer build() {
            return new NewComputer(this.cpu, this.screen, this.memory, this.mainboard);
        }

        public String toString() {
            return "NewComputer.NewComputerBuilder(cpu=" + this.cpu + ", screen=" + this.screen + ", memory=" + this.memory + ", mainboard=" + this.mainboard + ")";
        }
    }
}

可以看到,NewComputer提供了一个静态的公共方法builder,用于外部构造NewComputer.NewComputerBuilder,以下为测试代码:(读者可以自己加一个@ToString注解,便于测试)

NewComputer newComputer = NewComputer.builder() // 注意,这里不是new NewComputer.NewComputerBuilder()!!!
                .cpu("cpu")
                .memory("memory")
                .mainboard("mainboard")
                .build();
System.out.println(newComputer.toString());
// 结果:NewComputer(cpu=cpu, screen=null, memory=memory, mainboard=mainboard)

优缺点及适用场景

  • 优点:
    • 隔离用户与产品生产过程,符合开闭原则;
    • 使用静态内部类简化建造者模式,便于代码的书写;
    • 不需要了解复杂对象的内容,降低了学习成本;
    • 具体建造者之间是相互独立的,有利于系统的扩展;
  • 缺点:
    • 每次使用建造者模式都会多创建类,降低性能;
    • 若产品内部极其复杂,则可能创建很多具体建造者类来实现,系统会变得庞大;
  • 适用场景:
    • 对性能要求不高
    • 需要创建的产品有较多的共同点
    • 需要创建的类字段超过四个,建议使用建造者模式

以上就是对建造者模式的简要介绍,这里是10一世界,如果喜欢这篇文章,请点个赞吧!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值