设计模式——Builder建造者模式

329 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情

简述

属于创建型模式 ,将一个复杂的构建与其表示相分离,可以自行选择不同组合构建出想要的对象。

优点

  • 建造者独立,易扩展。
  • 便于控制细节风险。
  • 可以基于不同组合建造出各种各种各样的对象。

缺点

  • 产品需要有共同点,范围边界有限制。
  • 如果内部变化复杂会有很多的建造类。

实现

简单的Builder

需求:构建一个复杂地图,地图中包含堡垒、墙、矿等等,构建地图的使用者,需要构建各种各样的地图,且并不一定全都需要构建。

image-20220605185159517.png

Terrain对象,Fort、Mine、Wall以内部类的形式呈现

// 地图
public class Terrain {
    Wall w;
    Fort f;
    Mine m;
}
// 墙
class Wall {
    int x, y, w, h;
​
    public Wall(int x, int y, int w, int h) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
    }
}
// 堡垒
class Fort {
    int x, y, w, h;
​
    public Fort(int x, int y, int w, int h) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
    }
​
}
// 矿
class Mine {
    int x, y, w, h;
​
    public Mine(int x, int y, int w, int h) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
    }
}

TerrainBuilder接口,定义通用方法

public interface TerrainBuilder {
    TerrainBuilder buildWall();
    TerrainBuilder buildWall(int x, int y, int w, int h);
    TerrainBuilder buildFort();
    TerrainBuilder buildMine();
    Terrain build();
}

ComplexTerrainBuilder建造者实现类

public class ComplexTerrainBuilder implements TerrainBuilder {
​
    Terrain terrain = new Terrain();
​
    @Override
    public TerrainBuilder buildWall() {
        terrain.w = new Wall(10, 10, 50, 50);
        return this;
    }
​
    public TerrainBuilder buildWall(int x, int y, int w, int h) {
        terrain.w = new Wall(x, y, w, h);
        return this;
    }
​
    @Override
    public TerrainBuilder buildFort() {
        terrain.f = new Fort(10, 10, 50, 50);
        return this;
    }
​
    @Override
    public TerrainBuilder buildMine() {
        terrain.m = new Mine(10, 10, 50, 50);
        return this;
    }
​
    @Override
    public Terrain build() {
        return terrain;
    }
}

使用

使用的时候,可以根据需要构建不同的地图,比如我不需要Mine,就可以不构建Mine的build,可以自定义指定Wall的尺寸等

public class Main {
    public static void main(String[] args) {
        TerrainBuilder builder = new ComplexTerrainBuilder();
        Terrain t = builder
            .buildFort()
            .buildWall(1, 2, 3, 4)
            .build();
    }
}

实战Factory + Builder

在真实项目中我们很多对象的构建,可能时仅仅时new出来的,可能不少信息都是需要调用接口或者查询DB才能完全构建,因此通常会有Factory的角色,在factory里构建复杂对象。 在构建复杂对象时同样会遇到和Builder的需求,能够灵活组装的构建出想要的对象。

@Component
public class DemoFactory {
​
    DemoEntityBuilder builder(DemoListQuery demoListQuery) {
        // 转化成builder
        return new DemoEntityBuilder().init(demoListQuery);
    }
​
    @AllArgsConstructor
    @NoArgsConstructor
    public static class DemoEntityBuilder {
​
        DemoListQuery demoListQuery;
​
        List<DemoEntity> resultList;
​
        DemoEntityBuilder init(DemoListQuery demoListQuery){
            this.demoListQuery = demoListQuery;
            // TODO 根据条件查询DB 生成DemoEntity
            resultList = new ArrayList<>();
            return this;
        }
        
        public DemoEntityBuilder buildCreator(){
            return this;
        }
​
        public DemoEntityBuilder buildInfo(){
            return this;
        }
​
        public DemoEntityBuilder buildLocation(){
            return this;
        }
​
        public List<DemoEntity> build(){
            return resultList;
        }
​
    }
}
  • 在这种情况下,我们可以把builder内置在Factory中
  • Factory注入到Spring容器中,同时也免不了注入Repository和其他的Service来查询
  • 在init中进行DB查询,构建出领域对象
  • 然后通过各个build去组装领域对象中的详细信息

进阶

  • buildxxx中可以是用callabe,然后再build的中用线程池批量进行查询