设计模式-建造者模式(Builder)

设计模式-建造者模式(Builder)

   概要

   记忆关键词:类和构造分离

   定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

   分析:

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

   2)构建者模式的精髓是将复杂对象的构建过程封装到构建者里,使用构建者再去创建对象,即先有构建者后有产品,产品由构建者创建

   总体来说,建造者模式适用于需要创建具有复杂结构或多个配置选项的对象,而且希望将构建过程与表示分离的情况。

   建造者模式UML结构图如下:

        

   一、能解决什么问题?

   当一个对象的构造包含多个参数,尤其是这些参数有多种组合或依赖关系时,直接使用构造函数来创建对象会使代码变得难以维护和阅读。

   参数过多的构造函数会导致“构造函数爆炸”,即需要定义多个构造函数来处理不同的参数组合。

   二、涉及的角色

   1. Product(目标类)

   最终要生成的对象,代码示例如下:

 1 public class Product {
 2     ArrayList<String> parts = new ArrayList<>();
 3 
 4     public void add(String part) {
 5         parts.add(part);
 6     }
 7 
 8     public void show() {
 9         System.out.println(parts);
10     }
11 }

   2. Builder(建造者的抽象基类)

   承载了复杂对象的构建过程,代码示例如下: 

 1 public abstract class Builder {
 2 
 3     /**
 4      * 构建部分A
 5      */
 6     public abstract void buildPartA();
 7 
 8     /**
 9      * 构建部分B
10      */
11     public abstract void buildPartB();
12 
13     /**
14      * 获取展示结果
15      *
16      * @return 执行结果
17      */
18     public abstract Product getResult();
19

   3. ConcreteBuilder(具体的建造者)

   依赖Product类,ConcreteBuilder跟Product属于组合关系,ConcreteBuilder属于整体类,Product属于部分类

   代码示例如下: 

 1 public class ConcreteBuilder extends Builder {
 2 
 3     private final Product product = new Product();
 4 
 5     @Override
 6     public void buildPartA() {
 7         product.add("构建产品的上半部分");
 8     }
 9 
10     @Override
11     public void buildPartB() {
12         product.add("构建产品的下半部分");
13     }
14 
15     @Override
16     public Product getResult() {
17         return product;
18     }
19 }

   4. Director

   决定如何构建最终产品的算法。控制Builder的生产过程,Director跟Builder属于组合关系,Director属于整体类,Builder属于部分类。

   其会包含一个负责组装的方法void Construct(Builder builder), 在这个方法中通过调用builder的方法,就可以设置builder,等设置完成后,就可以通过builder的 getProduct() 方法获得最终的产品

   代码示例如下:

 1 public class Director {
 2     private final Builder builder;
 3 
 4     public Director(Builder builder) {
 5         this.builder = builder;
 6     }
 7 
 8     public void construct() {
 9         builder.buildPartA();
10         builder.buildPartB();
11     }
12 }

   客户端调用:

 1 public class Client {
 2     public static void main(String[] args) {
 3 
 4         ConcreteBuilder concreteBuilder = new ConcreteBuilder();
 5 
 6         //控制Builder的生产过程
 7         Director director = new Director(concreteBuilder);
 8         director.construct();
 9 
10         Product product = concreteBuilder.getResult();
11         product.show();
12     }
13 }
14 
15 
16 //运行结果
17 [构建产品的上半部分, 构建产品的下半部分]

  再来一个简化建造者模式的使用案例:

  Computer类:

 1 public class Computer {
 2 
 3     /**
 4      * 必须字段
 5      */
 6     private final String cpu;
 7 
 8     /**
 9      * 必须字段
10      */
11     private final String ram;
12 
13     /**
14      * 可选字段
15      */
16     private final int usbCount;
17 
18     /**
19      * 可选字段
20      */
21     private final String keyboard;
22 
23     /**
24      * 可选字段
25      */
26     private final String display;
27 
28     public Computer(Builder builder) {
29         this.cpu = builder.cpu;
30         this.ram = builder.ram;
31         this.usbCount = builder.usbCount;
32         this.keyboard = builder.keyboard;
33         this.display = builder.display;
34     }
35 
36     @Override
37     public String toString() {
38         return "Computer{" +
39                 "cpu='" + cpu + '\'' +
40                 ", ram='" + ram + '\'' +
41                 ", usbCount=" + usbCount +
42                 ", keyboard='" + keyboard + '\'' +
43                 ", display='" + display + '\'' +
44                 '}';
45     }
46 
47     public static class Builder {
48         /**
49          * 必须字段
50          */
51         private final String cpu;
52 
53         /**
54          * 必须字段
55          */
56         private final String ram;
57 
58         /**
59          * 可选字段
60          */
61         private int usbCount;
62 
63         /**
64          * 可选字段
65          */
66         private String keyboard;
67 
68         /**
69          * 可选字段
70          */
71         private String display;
72 
73         public Builder(String cpu, String ram) {
74             this.cpu = cpu;
75             this.ram = ram;
76         }
77 
78         public Builder setUsbCount(int usbCount) {
79             this.usbCount = usbCount;
80             return this;
81         }
82 
83         public Builder setKeyboard(String keyboard) {
84             this.keyboard = keyboard;
85             return this;
86         }
87 
88         public Builder setDisplay(String display) {
89             this.display = display;
90             return this;
91         }
92 
93         public Computer build() {
94             return new Computer(this);
95         }
96     }
97 }

  客户端类Client:

 1 public class Client {
 2     public static void main(String[] args) {
 3         Computer computer = new Computer.Builder("因特尔", "三星")
 4                 .setUsbCount(2)
 5                 .setKeyboard("罗技")
 6                 .setDisplay("LG28寸")
 7                 .build();
 8         System.out.println(computer.toString());
 9     }
10 }
11 
12 //运行结果
13 Computer{cpu='因特尔', ram='三星', usbCount=2, keyboard='罗技', display='LG28寸'}

  四、使用场景

  在Java源码里,建造者模式最典型的体现就是StringBuilder

  StringBuilder是Java中的一个用于构建字符串的类,它允许在不创建新的对象的情况下,对字符串进行可变操作。它通过提供一系列方法来逐步构建字符串,并通过链式调用使代码简洁易读。

  代码示例如下:

 1 public class StringBuilderExample {
 2     public static void main(String[] args) {
 3         StringBuilder builder = new StringBuilder();
 4         
 5         builder.append("Hello, ")
 6                .append("world")
 7                .append("!")
 8                .insert(7, "Java ")
 9                .replace(13, 18, "World")
10                .deleteCharAt(6);
11         
12         String result = builder.toString();
13         System.out.println(result); // 输出: "Hello Java World!"
14     }
15 }

  注意:lombok中的@Builder 注解通过注入一个静态内部类作为建造者,简化了建造者模式的使用,减少了样板代码。这种方式在代码中使用起来更加简洁,并且提高了可读性。

  举个例子:

  给User类加上@Data和@Builder注解

1 @Data
2 @Builder
3 public class User {
4     private String name;
5     private int age;
6

  通过IDEA的Delombok功能,右键点击并选择 Refactor -> Delombok, 选择 @Builder 查看代码:

 1 @Data
 2 public class User {
 3     private String name;
 4     private int age;
 5 
 6     User(String name, int age) {
 7         this.name = name;
 8         this.age = age;
 9     }
10 
11     public static UserBuilder builder() {
12         return new UserBuilder();
13     }
14 
15     public static class UserBuilder {
16         private String name;
17         private int age;
18 
19         UserBuilder() {
20         }
21 
22         public UserBuilder name(String name) {
23             this.name = name;
24             return this;
25         }
26 
27         public UserBuilder age(int age) {
28             this.age = age;
29             return this;
30         }
31 
32         public User build() {
33             return new User(name, age);
34         }
35 
36         public String toString() {
37             return "User.UserBuilder(name=" + this.name + ", age=" + this.age + ")";
38         }
39     }
40 }

  客户端类: 

 1 public class Client {
 2     public static void main(String[] args) {
 3         User user = User.builder()
 4                 .name("tom")
 5                 .age(18)
 6                 .build();
 7         System.out.println(user);
 8     }
 9 }
10 
11 // 运行结果
12 User(name=tom, age=18)

  五、建造者模式与简单工厂模式的区别

  两者的区别在于,建造者模式多出一个Builder类,使得创建对象的灵活性大大增加,适用于如下场景:

  1. 创建一个对象,多个同样的方法的调用顺序不同,产生的结果不同

  2. 创建一个对象,特别复杂,参数多,而且很多参数都有默认值

posted @ 2024-07-24 13:51  欢乐豆123  阅读(47)  评论(0编辑  收藏  举报