# 链式编程、建造者模式、代码模板等

# 链式编程

为什么要使用 Java 链式编程呢?我们在 Java 语言编程的过程中,肯定少不了创建对象的,但是创建对象后,我们设置属性需要不停的使用对象 .setXXX( ) 方法,然后再换行继续使用对象 .setXXX( ) 方法,这样创建出来的对象需要被我们重复的写很多遍,效率低而且代码可读性也很差,怎么能让我们代码能不用重复书写对象而更优雅的编写出来呢,链式编程就能帮我们实现这个效果,我们可以在创建对象后直接在后面.

# 链式编程的优缺点

链式编程可以让代码的可读型变高,链式编程也比较好实现,原理也就是返回一个 this 对象,即返回对象本身,这样就可以达到链式的效果;

优点:

  • 编程型强
  • 可读性强
  • 代码更简洁

缺点:

  • 不利于代码调试
  • 对程序员业务能力要求变高
# Java 对流式编程的实现
# 达到的效果
目标效果
public class Student{
    private Integer id;
    private String name;
    private String email;
    private String phone;
    /**
    setter/getter 方法省略
    */
}
...
Student s = new Student();
s.setId(1);
s.setEmail("xxxx@123.com");
s.setName("zhangsan");
user.setPhone("1135654635");
# 实现方法

方法 1:改写 setter 方法

通过简单的改造让 set方法 返回对象本身,这样就可以再进行调用;

方法1(改写set方法)
// 原来的 set 方法
//public void setId(Integer id){
//	this.id =id;
//} 
public Student setId(Integer id) {
        this.id = id;
        return this;
    }
public Student setName(String name) {
        this.name = name;
        return this;
    }
public Student setEmail(String email) {
        this.email = email;
        return this;
    }
public Student setPhone(String phone) {
        this.phoneNum = phone;
        return this;
    }

方法 2:lombok 实现

增加 @Accessors(chain = true) 注解就可开启链式编程了。

方法2(lombok实现)
@Accessors(chain = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student{
    private Integer id;
    private String name;
    private String email;
    private String phone;
}

# 建造者模式

建造者模式是一步一步构造复杂对象,它允许用户只通过指定复杂对象的类型和内容就可以构造他们,用户不需要指定内部的具体构建细节。

image-20230523092044199

在建造者模式结构图中包含如下几个角色:

  • Builder(抽象构造者):它为创建一个产品 Product 对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是 buildPartX() ,它们用于创建复杂对象的各个部件;另一类方法是 getResult() ,它们用于返回复杂对象。Builder 既可以是抽象类,也可以是接口。

  • ConcreteBuilder(具体构造者):它实现了 Builder 接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。

  • Product(产品角色):他是被构造的复杂对象 ,包含多个组成部件具体构造者创建该产品的内部表示并定义它的装配过程。

  • Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其 construct () 建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者 Setter 方法将该对象传入指挥者类中。

对象类代码示例如下:

对象类代码示例
class Product  {
       private  String partA; // 定义部件,部件可以是任意类型,包括值类型和引用类型
       private  String partB;
       private  String partC;
       //partA 的 Getter 方法和 Setter 方法省略
       //partB 的 Getter 方法和 Setter 方法省略
       //partC 的 Getter 方法和 Setter 方法省略
}

在抽象建造者类中定义了产品的创建方法和返回方法,其典型代码如下:

abstract class Builder {
     // 创建产品对象
       protected  Product product=new Product();
       public  abstract void buildPartA();
       public  abstract void buildPartB();
       public  abstract void buildPartC();
     // 返回产品对象
       public  Product getResult() {
              return  product;
       }
}

在抽象类 Builder 中声明了一系列抽象的 buildPartX () 方法用于创建复杂产品的各个部件,具体建造过程在 ConcreteBuilder 中实现,此外还提供了工厂方法 getResult (),用于返回一个建造好的完整产品。

在 ConcreteBuilder 中实现了 buildPartX () 方法,通过调用 Product 的 setPartX () 方法可以给产品对象的成员属性设值。不同的具体建造者在实现 buildPartX () 方法时将有所区别,如 setPartX () 方法的参数可能不一样,在有些具体建造者类中某些 setPartX () 方法无须实现(提供一个空实现)。而这些对于客户端来说都无须关心,客户端只需知道具体建造者类型即可。

在建造者模式的结构中还引入了一个指挥者类 Director,该类主要有两个作用:一方面它隔离了客户与创建过程;另一方面它控制产品的创建过程,包括某个 buildPartX () 方法是否被调用以及多个 buildPartX () 方法调用的先后次序等。指挥者针对抽象建造者编程,客户端只需要知道具体建造者的类型,即可通过指挥者类调用建造者的相关方法,返回一个完整的产品对象。在实际生活中也存在类似指挥者一样的角色,如一个客户去购买电脑,电脑销售人员相当于指挥者,只要客户确定电脑的类型,电脑销售人员可以通知电脑组装人员给客户组装一台电脑。指挥者类的代码示例如下:

class Director {
       private  Builder builder;
       public  Director(Builder builder) {
              this.builder=builder;
       }
       public  void setBuilder(Builder builder) {
              this.builder=builer;
       }
       // 产品构建与组装方法
       public Product construct() {
              builder.buildPartA();
              builder.buildPartB();
              builder.buildPartC();
              return builder.getResult();
       }
}

在指挥者类中可以注入一个抽象建造者类型的对象,其核心在于提供了一个建造方法 construct (),在该方法中调用了 builder 对象的构造部件的方法,最后返回一个产品对象。

对于客户端而言,只需关心具体的建造者即可,一般情况下,客户端类代码片段如下所示:

……
Builder  builder = new ConcreteBuilder(); // 可通过配置文件实现
Director director = new  Director(builder);
Product product = director.construct();
……