今天看netty權威指南,第一次聽說構建器,百度了幾個博客,但是並沒有通俗易懂一點兒的,綜合別人的博客,總結如下:
1. 構建器是什么?
當創建對象需要傳入多個參數的時候我們通常會根據參數的數量寫不同的構造器,具體如下
public A(int a){}
public A(int a, int b){}
public A(int a, int b, int c){}
根據不同的參數調用不同的構造器,但是當參數多了的時候,這種方式不夠靈活,所以會實現動態傳參的方法
public A(){}
public void seta(int a){}
public void setb(int b){}
public void setc(int c){}
這種方式提高了傳參的可讀性,也提高了傳參的靈活性,但是會增加代碼行數,同時在多線程異步執行的時候導致奇怪的錯誤。
有沒有辦法解決呢?既能提高代碼可讀性,提高參數靈活性,又不會增加代碼行數,並保證線程安全呢?
構建器模式登場,先看代碼。
這里我們寫一個 Person 類,並為這個類加上構建器:
- public class Person {
- private final String name;
- private final int age;
-
- private final String address;
- private final String phone;
-
- public static class Builder{
- private final String name;
- private final int age;
-
- private String address = null;
- private String phone = null;
-
- public Builder(String name,int age){
- this.name = name;
- this.age = age;
- }
-
- public Builder address(String val){
- address = val;
- return this;
- }
-
- public Builder phone(String val){
- phone = val;
- return this;
- }
-
- public Person builder(){
- return new Person(this);
- }
- }
-
- private Person(Builder builder){
- this.name = builder.name;
- this.age = builder.age;
- this.address = builder.address;
- this.phone = builder.phone;
- }
-
- @Override
- public String toString() {
- return "name:"+name+" age:"+age+" address:"+address+" phone:"+phone;
- }
-
- }
調用這個構建器的方式
public class PersonTest { public static void main(String[] args) { Person p = new Person.Builder("tom", 18).address("深圳").phone("110").builder(); System.out.println(p.toString()); } }
2. 為什么使用構建器?
2.1 參數的限制
靜態工廠方法與構造器都有一個共同的局限性,就是它們不能很好的擴展到大量的可選參數。就像我們上面的那個Person 類,在實際中我們會有許多的屬性,性別、出生年月、愛好...對與這樣的類。
2.2 重疊構造器
我們初學的時候都會選擇 重疊構造器(telecoping constructor)模式 。在這種情況下,第一個構造器是實例化對象必須的參數,第二個會多一個參數,就這樣疊加,最后是一個有所有參數的構造器
- public class Person {
- private final String name;
- private final int age;
-
- private final String address;
- private final String phone;
-
- public Person(String name, int age) {
- this(name,age,null);
- }
-
-
- public Person(String name, int age, String address) {
- this(name,age,address,null);
- }
-
- public Person(String name, int age, String address, String phone) {
- super();
- this.name = name;
- this.age = age;
- this.address = address;
- this.phone = phone;
- }
-
- @Override
- public String toString() {
- return "name:"+name+" age:"+age+" address:"+address+" phone:"+phone;
- }
-
- }
獲得對象
public class PersonTest { public static void main(String[] args) { Person p = new Person("tom",18,null,"110"); System.out.println(p.toString()); } }
在這個構造器中也許會有你不想要的參數,如果我們的參數變多了的話,情況就不會很好。
總結一句話:重疊構造器可行,但當有很多的參數的時候,客戶端的代碼就會很難編寫並且不容易閱讀我們在使用的時候,必須很仔細的看每一個參數的位置和含義。
2.3 JavaBeans模式
2.3.1 創建JavaBeans模式
這個時候我們還有一種替代的方式,這個就是JavaBeans模式。這種模式下,使用無參的構造方法創建對象,然后調用setter 方法給屬性設置值
- public class Person {
- private String name;
- private int age;
-
- private String address;
- private String phone;
-
- public void setName(String name) {
- this.name = name;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public void setAddress(String address) {
- this.address = address;
- }
- public void setPhone(String phone) {
- this.phone = phone;
- }
-
- @Override
- public String toString() {
- return "name:"+name+" age:"+age+" address:"+address+" phone:"+phone;
- }
-
- }
使用的方式,這個相比與重疊構造器更容易的創建了對象,同時讓代碼跟容易的閱讀。
public class PersonTest { public static void main(String[] args) { Person p = new Person(); p.setName("tom"); p.setAge(18); p.setAddress("深圳"); p.setPhone("110"); System.out.println(p.toString()); } }
2.3.2 JavaBeans模式的劣勢
構造的過程分到了幾個調用中,在構造JavaBeans的時候可能會不一致
類無法僅僅通過檢驗構造器參數的有效性來保證一致性!
對象的不一致會導致失敗,JavaBeans模式阻止了把類做為不可變的可能,需要程序員做額外努力來保證它線程安全。
2.4 構建器
構建器的創建對象就比較易於創建與閱讀,線程安全
等待所有的參數驗證通過才會build()對象。
與構造器相比,builder 的微略優勢在於,builder可以有多個可變(varargs)參數。構造器像方法一樣,只有一個可變參數。因為builder利用單獨的方法來設置每個參數,你想要多少個可變參數,他們就可以有多少個,知道每個setter方法都有一個可變參數。
builder模式非常靈活,可以理由單個builder構建多個對象。builder的參數可以在創建對象時進行調整
設置了參數的builder生成一個很好的抽象工廠(Abstract Factory),也就是客戶端可以將這樣一個builder傳給方法,使該方法能為客戶端創建一個或者多個對象
builder也有自己的不足,就是創建對象就必須創建它的構建器。
builder模式還比重疊構造器模式更加的冗長,因此它會在參數多的時候使用。但是我們要知道,我們可能會在設計之后還要添加參數,所以一開始就用構建器還是比較好的。
3 總結
如果類的構造器或者靜態工廠中具有多個參數,設計這種類時,Builder模式就是不錯的選擇,特別是當大多數14:39:30參數都是可選的時候。
與重疊構造器相比,builder牧師的客戶端更易與閱讀和編寫
與JavaBeans相比,更加的安全
