4

lombok中的builder注解居然是一种设计模式:让我们了解一下超级实用的“建造者模式”吧

 2 years ago
source link: https://my.oschina.net/alicoder/blog/5354635
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

lombok中的builder注解居然是一种设计模式:让我们了解一下超级实用的“建造者模式”吧 - 程序员江湖 - OSCHINA - 中文开源技术交流社区

 lombok中的builder注解本质上是为你生成了一个构造器Builder类,通过这个类我们可以构造出带此注解的对象。本质上它实现了设计模式中一种经典的模式:建造者模式

1.认识:

①一句话来说:封装一个复杂对象的构建过程,并可以按步骤构造。因为需要对对象一步步建造起来,所以称为建造者模式。

②将复杂产品的构建过程封装分解在不同的方法中,使得创建过程非常清晰,能够让我们更加精确的控制复杂产品对象的创建过程,同时它隔离了复杂产品对象的创建和使用,使得相同的创建过程能够创建不同的产品。但是若内部变化复杂,会有很多的建造类。

2.UML类图:

图片

UML说明:Product(产品角色):一个具体的产品对象。Builder(抽象建造者):创建一个Product对象的各个部件指定的抽象接口。ConcreteBuilder(具体建造者):实现抽象接口,构建和装配各个部件。Director(指挥者):构建一个使用Builder接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。

3.代码如下:

1.产品类:

public class Product {
    private String part1;//可以是任意类型
    private String part2;
    private String part3;
 /**set get 方法省略
}

2.抽象建造者

public abstract class Builder{

    Product product = new Product();
    public abstract void buildPart1();
    public abstract void buildPart2();
    public abstract void buildPart3();
    public Product getResult(){
        return product;
    };
}

3.具体建造者

public class ConcreteBuilder extends Builder {

    @Override
    public void buildPart1() {
        System.out.println("建造part1");
    }

    @Override
    public void buildPart2() {
        System.out.println("建造part2");
    }

    @Override
    public void buildPart3() {
        System.out.println("建造part3");
    }
}

4.指挥者:

public class Director {

    private Builder builder;

    public Director(Builder builder) {
        this.builder = builder;
    }

    public Product build(){
        builder.buildPart1();
        builder.buildPart2();
        builder.buildPart3();
        return builder.getResult();
    }
}

5.客户端

public class Client {

    @Test
    public void test() {
        Builder builder = new ConcreteBuilder();
        Director director = new Director(builder);
        director.build();
    }

}

6.执行结果

图片

优点:1、建造者独立,易扩展。将复杂产品的构建过程封装分解在不同的方法中,使得创建过程非常清晰,能够让我们更加精确的控制复杂产品对象的创建过程。

2、便于控制细节风险。它隔离了复杂产品对象的创建和使用,使得相同的创建过程能够创建不同的产品。

缺点:1、产品必须有共同点,范围有限制。

2、如内部变化复杂,会有很多的建造类,导致系统庞大。

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

5.应用场景

JAVA 中的 StringBuilder。

六、个人体会

设计模式是一种解决问题的思维和方式,不要生搬硬套,为了设计模式而模式。

PS:转载请注明出处 作者: TigerChain 地址: www.jianshu.com/p/300cbb9ee… 本文出自 TigerChain 简书 人人都会设计模式

  • 1、阅读对象 本篇教程适合新手阅读,老手直接略过
  • 2、教程难度 初级,本人水平有限,文章内容难免会出现问题,如果有问题欢迎指出,谢谢
  • 3、Demo 地址:github.com/githubchen0…

一、什么是建造者模式

1、生活中的建造者模式

1、盖房子

我们在生活中盖房子,一般就是打地基,盖框架「用砖头或钢筋混凝土」,然后是粉刷。基本上就是这个路子。当然我们这些工作全部可以自己做,可也以找几个工人去干,当然还可以可以直接找一个设计师,直接说我就要这样的房子,然后就不管了,最后问设计师「设计师给一张纸给工人,工人就啪啪的干了」验收房子即可「至于你是如何建的过程我不关心,我只要结果」---这就是建造者模式

2、组装电脑

我们买的电脑都是由主板、内存、cpu、显卡等组成,如何把这些东西组装起来给用户这就是建造者模式的作用,不同的人对电脑的配置需求不一样的「打游戏的对显卡要求高」,但是电脑构成部件是固定的,我们找电脑城的装机人员把电脑装起来这一过程就是建造模式

3、软件开发

我们开发一款产品,需要技术主管、产品经理、苦逼的程序员。在这里,产品经理就是指挥者「Director」和客户沟通,了解产品需求,技术主管是抽象的建造者[Builder],让猿们杂做就杂做,而程序员就是体力劳动者「即具体的建造者,按照技术主管下发的任务去做」--- 这就是一个接近完美的建造者模式「为什么说接近呢?因为没有百分之百,靠:又忘记吃药了」

2、程序中的建造者模式

建造者模式的定义

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,这是官方定义,通俗的说就是:建造者模式就是如何一步步构建一个包含多个组成部件的对象,相同的构建过程可以创建不同的产品

建造者模式的特点

建造者模式是一种创建型模式,适用于那些流程固定「顺序不一定固定」,建造的目标对象会有所改变这种场景「比如画一条狗,这个目标不变,但是不同的是有黄狗,胖狗,瘦狗等」,还有一种场景是代替多参数构造器

建造者模式的作用

  • 1、用户不知道对象的建造过程和细节就可以创建出复杂的对象「屏蔽了建造的具体细节」
  • 2、用户只需给出复杂对象的内容和类型可以创建出对象
  • 3、建造者模工按流程一步步的创建出复杂对象

建造者模式的结构

角色 类别 说明 Builder 接口或抽象类 抽象的建造者,不是必须的 ConcreateBuilder 具体的建造者 可以有多个「因为每个建造风格可能不一样」 Product 普通的类 具体的产品「即被建造的对象」 Director 导演也叫指挥者 统一指挥建造者去建造目标,导演不是必须的

建造者模式简单的 UML

建造者模式简单的 UML

二、建造者模式的举例

1、组装电脑

小明想组装一个台式电脑,小明对电脑配置一窍不通,就直接跑到电脑城给装机老板说我要一台打游戏非常爽的电脑,麻烦你给装一下「配置什么的你给我推荐一下吧」,于是老板就让它的员工「小美」按小明的要求装了一个性能灰常牛 B 的电脑,1 个小时后电脑装好了,小明交钱拿电脑走人。不一会儿小张又来了,要一个满足平时写文章就可以的电脑,老板针对小张的要求给不同的装机配置。不同的人有不同的配置方案「但是装机流程是一样的」,这就是一个典型的建造者模式

组装电脑简单的 UML

组装电脑简单的 UML

根据 UML 撸码

  • 1、创建被建造的对象电脑 --- Computer.java
/**
 * Created by TigerChain
 * 产品类--被建造的对象
 */
public class Computer {
    private String cpu ; // cpu
    private String hardDisk ; //硬盘
    private String mainBoard ; // 主板
    private String memory ; // 内存
    ... 省略 getter 和 setter
}
复制代码
  • 2、抽象的建造者 --- Builder.java
/**
 * Created by TigerChain
 * 抽象的建造者,即装电脑的步骤
 * 至于安装什么型号的主板,不是我关心,而是具体的建造者关心的
 */
public interface Builder {
    // 安装主板
    void createMainBoard(String mainBoard) ;
    // 安装 cpu
    void createCpu(String cpu) ;
    // 安装硬盘
    void createhardDisk(String hardDisk) ;
    // 安装内存
    void createMemory(String memory) ;
    // 组成电脑
    Computer createComputer() ;
}

复制代码
  • 3、具体建造者,也就是装机工人小美 --- AssemblerBuilder.java
/**
 * Created by TigerChain
 * 具体的建造者,这里是商场的一个装机人员
 */
public class AssemblerBuilder implements Builder {

    private Computer computer = new Computer() ;
    @Override
    public void createCpu(String cpu) {
        computer.setCpu(cpu);
    }

    @Override
    public void createhardDisk(String hardDisk) {
        computer.setHardDisk(hardDisk);
    }

    @Override
    public void createMainBoard(String mainBoard) {
        computer.setMainBoard(mainBoard);
    }

    @Override
    public void createMemory(String memory) {
        computer.setMemory(memory);
    }

    @Override
    public Computer createComputer() {
        return computer;
    }
}
复制代码
  • 4、还有老板「"指手画脚的人"」安排装机工工作 --- Direcror.java
/**
 * Created by TigerChain
 * 声明一个导演类「指挥者,这里可以装电脑的老板」,用来指挥组装过程,也就是组装电脑的流程
 */
public class Director {
    private Builder builder ;
	// 使用多态,装机工非常多,我管你小美,小兰,小猪,我统统收了
    public Direcror(Builder builder){
        this.builder = builder ;
    }
	// 老板最后只想看到装成的成品---要交到客户手中
    public Computer createComputer(String cpu,String hardDisk,String mainBoard,String memory){
        // 具体的工作是装机工去做
        this.builder.createMainBoard(mainBoard);
        this.builder.createCpu(cpu) ;
        this.builder.createMemory(memory);
        this.builder.createhardDisk(hardDisk);
        return this.builder.createComputer() ;
    }
}
复制代码
  • 5、测试类
/**
 * Created by TigerChain
 * 测试类
 */
public class Test {
  public static void main(String args[]){
	  // 装机员小美
      Builder builder = new AssemblerBuilder() ;
      // 老板把小明的需求转给小美
      Direcror direcror = new Direcror(builder) ;
      // 老板最后拿到成品机子,工作全由小美去做
      Computer computer = direcror.createComputer("Intel 酷睿i9 7900X","三星M9T 2TB (HN-M201RAD)","技嘉AORUS Z270X-Gaming 7","科赋Cras II 红灯 16GB DDR4 3000") ;
      System.out.println("小明这台电脑使用的是:\n"+computer.getMainBoard()+" 主板\n"+computer.getCpu()+" CPU\n"+computer.getHardDisk()+"硬盘\n"+computer.getMainBoard()+" 内存\n");

  }
}
复制代码
  • 6、运行查看结果

装机结果

怎么样,至于小张,小猪要装机把自己要的配置给老板即可,然后老板如何装机不用你管,你就等着收装好的机子吧

2、盖房子

盖房子的基本步骤和流程是固定的无非就是打地基、盖框架、然后浇筑「至于盖平房、还是楼房那是每个客户的具体需求」。总体来说盖房子以有以三种方式:

  • 1、自己盖房子「没有办法有的人就是牛 B ,自己设计,自己动手,当然这属于小房子,你让一个人盖个32 层让我看看」
  • 2、想盖房子的人是一个包工头,自己找一帮工人自己就把房子搞定了
  • 3、想盖房子的人就是一个普通人,啥也不会,找一个设计师说“我就要盖个房子,南北通透,四秀常春”,设计师说没有问题,设计师把设计出来的图纸扔给包工头说:“就照这个样子盖”,包工头拿着图纸给工人们分工派活,最后完工

盖房子建造者模式简单的 UML

盖房子建造者模式简单的 UML

根据 UML 撸码

  • 1、房子对象 House.java
/**
 * Created by TigerChain
 * 最终的产品---房子
 */
public class House {
    // 打地基
    private String foundation ;
    // 盖框架
    private String frame ;
    // 浇筑
    private String pouring ;
    ... 省略 setter 和 getter 
}
复制代码
  • 2、抽象建造者「包工头」 HouseBuilder.java
public interface HouseBuilder {
    // 打地基
    void doFoundation() ;
    // 盖框架
    void doFrame() ;
    // 浇灌
    void dpPouring() ;
    // 房子建成 
    House getHouse() ;
}
复制代码
  • 3、具体建造者「工人」--盖平房 PingFangBuilder.java
/**
 * Created by TigerChain
 * 盖平房
 */
public class PingFangBuilder implements HouseBuilder {

    private House house = new House() ;

    @Override
    public void doFoundation() {
        house.setFoundation("盖平房的地基");
    }

    @Override
    public void doFrame() {
        house.setFrame("盖平房的框架");
    }

    @Override
    public void dpPouring() {
        house.setPouring("盖平房不用浇灌,直接人工手刷就可以");
    }

    @Override
    public House getHouse() {
        return house;
    }
}
复制代码
  • 4、具体建造者「工人」--盖楼房 LouFangBuilder.java
/**
 * Created by TigerChain
 * 盖楼房
 */
public class LouFangBuilder implements HouseBuilder {

    private House house = new House() ;
    @Override
    public void doFoundation() {
        house.setFoundation("盖楼房的地基就打十米深");
    }

    @Override
    public void doFrame() {
        house.setFrame("楼房的框架要使用非常坚固钢筋混凝土");
    }

    @Override
    public void dpPouring() {
        house.setPouring("楼房拿个罐车把框架拿混凝土灌满即可");
    }

    @Override
    public House getHouse() {
        return house;
    }
}
复制代码
  • 5、指挥者「设计师」 HouseDirector.java
/**
 * Created by TigerChain
 * 设计师
 */
public class HouseDirector {
    // 指挥包工头
    public void buildHouse(HouseBuilder houseBuilder){
        houseBuilder.doFoundation();
        houseBuilder.doFrame();
        houseBuilder.dpPouring();
    }
}

复制代码
  • 6、测试一下 Test.java
/**
 * Created by TigerChain
 * 测试
 */
public class Test {
    public static void main(String args[]){

        // 方式一、客户自己盖房子,亲力亲为
        System.out.println("========客户自己建房子,必须知道盖房的细节========");
        House house = new House() ;
        house.setFoundation("用户自己建造房子:打地基");
        house.setFrame("用户自己建造房子:盖框架");
        house.setPouring("用户自己建造房子:浇筑");

        System.out.println(house.getFoundation());
        System.out.println(house.getFrame());
        System.out.println(house.getPouring());

        // 方式二、客户找一个建造者盖房子「充当包工头角色」,但是要知道如何盖房子「调用建造者盖房子的顺序」
        System.out.println("========客户直接找盖房子的工人「建造者」,客户要调用建造者方法去盖房子,客户必须得知道房子如何造========");

        HouseBuilder houseBuilder = new PingFangBuilder() ;
        houseBuilder.doFoundation();
        houseBuilder.doFrame();
        houseBuilder.dpPouring();
        House house1 = houseBuilder.getHouse() ;
        System.out.println(house1.getFoundation());
        System.out.println(house1.getFrame());
        System.out.println(house1.getPouring());

        // 方式三、使用建造者模式,找一个设计师「设计师拉一帮建造者去干活」,告诉他我想要什么样的房子,最后客户只问设计师要房子即可
        System.out.println("========客户直接找一个设计师,设计师统一指挥建造者盖房子,房子杂盖,客户不关心,最后只是找设计师要房子即可========");

        HouseBuilder pingFangBuilder = new PingFangBuilder() ;
        HouseDirector houseDirector = new HouseDirector() ;
        houseDirector.buildHouse(pingFangBuilder);
        House houseCreateByBuilder = pingFangBuilder.getHouse() ;

        System.out.println(houseCreateByBuilder.getFoundation());
        System.out.println(houseCreateByBuilder.getFrame());
        System.out.println(houseCreateByBuilder.getPouring());
    }
}

复制代码

我们对比了三种方式,自己盖房子,找工人盖房子,找设计师盖房子来逐步感受一下建造者模式的优点

  • 6、运行查看结果

盖房子结果

可以看到最后一种最舒服,盖房子的时候直接外包给设计师自己就不用管了,到时候问设计师要建好的成品房子即可,这样对客户来说具体如何盖房子我不需要知道,屏蔽细节「只能说有钱就是任性」


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK