使用Builder設計模式實現不變性 - DZone Java
Effective Java的一條建議是,除非有充分的理由讓它們變得可變,否則你應該讓你的類不可變。如果一個類不能成為不可變的,那麼儘可能地限制它的可變性。不可變類定義了一旦建立,就永遠不會改變其狀態的物件。所有狀態資訊都是在構造物件時提供的,並且在物件的生命週期內不會改變。
我們為什麼要編寫不可變類?
不可變類提供了許多優於可變類的優點。這些是:
- 不可變物件簡單易用,因為它只能處於一個狀態,即建立它的狀態。
- 它們本質上是執行緒安全的,即它們不需要同步。
- 不可變類的物件可以自由共享。例如,Boolean類重用其現有例項TRUE和FALSE,每當呼叫Boolean.valueOf方法時,它都會為您提供已建立的例項。
建立一個不可變類
一個簡單的不可變類可以是這樣的:
public final class User { private final String username; private final String password; public User(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public String getPassword() { return password; } } |
這個類是不可變的,因為:
- 它不提供setter方法或mutator。
- Class不能擴充套件,因為它是最終的。這也可以透過使建構函式私有來完成。
- class的欄位都是最終的和私人的。
值得注意的是,這個類非常簡單,只有兩個欄位。在我們的實際應用程式的大多數類中,有兩個以上的欄位。此外,大多數這些欄位對於物件建立不是必需的。例如,真實應用程式中的使用者將具有使用者名稱,密碼,名字,姓氏,creationDate,emailAddress等,但是對於此處的使用者建立,僅需要使用者名稱和密碼。所以,我們設計我們的類如下所示:
final class User { private final String username; private final String password; private String firstname; private String lastname; private String email; private Date creationDate; public User(String username, String password) { this.username = username; this.password = password; creationDate = new Date(); } public String getUsername() { return username; } public String getPassword() { return password; } public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } public String getLastname() { return lastname; } public void setLastname(String lastname) { this.lastname = lastname; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Date getCreationDate() { return new Date(creationDate.getTime()); } } |
這個類不是不可變的,因為它有mutators,即setter。因此,可以在建立後修改此類的例項。這種方法的缺點是,物件可能處於不一致的狀態,透過它們的構造方式,你必須付出額外的努力來確保執行緒安全。
Builder Design Pattern來救援
據Gof說:
構建器模式將複雜物件的構造與其表示分開,以便相同的構造過程可以建立不同的表示。
構建器設計模式為您提供了構建複雜不可變物件的方法。過程是:
- 客戶端使用所有必需引數呼叫建構函式(或靜態工廠)並獲取構建器物件。
- 客戶端呼叫setter之類的方法來設定每個感興趣的可選引數。
- 最後,客戶端呼叫構建方法來生成不可變的物件。
不可變的使用者:
public class ImmutableUser { private final String username; private final String password; private final String firstname; private final String lastname; private final String email; private final Date creationDate; private ImmutableUser(UserBuilder builder) { this.username = builder.username; this.password = builder.password; this.creationDate = builder.creationDate; this.firstname = builder.firstname; this.lastname = builder.lastname; this.email = builder.email; } public String getUsername() { return username; } public String getPassword() { return password; } public String getFirstname() { return firstname; } public String getLastname() { return lastname; } public String getEmail() { return email; } public Date getCreationDate() { return new Date(creationDate.getTime()); } public static class UserBuilder { private final String username; private final String password; private final Date creationDate; private String firstname; private String lastname; private String email; public UserBuilder(String username, String password) { this.username = username; this.password = password; this.creationDate = new Date(); } public UserBuilder firstName(String firsname) { this.firstname = firsname; return this; } public UserBuilder lastName(String lastname) { this.lastname = lastname; return this; } public UserBuilder email(String email) { this.email = email; return this; } public ImmutableUser build() { return new ImmutableUser(this); } } } |
您還應檢查構建方法中的不變數,如果任何屬性無效,則丟擲IllegalStateException。這將確保物件在例項化後處於可工作狀態。
public static void main(String[] args) { ImmutableUser user = new ImmutableUser.UserBuilder("shekhar", "password").firstName ("shekhar").lastName("gulati").email("shekhargulati84@gmail.com").build(); } |
透過這種方式,您可以構建一個不可變的複雜物件,並具有不可變物件的所有優點。
相關文章
- Java設計模式之builder模式Java設計模式UI
- Java 高效程式設計之 Builder 模式Java程式設計UI模式
- 設計模式:Builder模式概述設計模式UI
- 設計模式:單例模式的使用和實現(JAVA)設計模式單例Java
- 設計模式-建造者模式(Builder)設計模式UI
- 設計模式實戰系列之@Builder和建造者模式設計模式UI
- 設計模式-生成器模式Builder設計模式UI
- 【設計模式】- 生成器模式(Builder)設計模式UI
- 設計模式--建造者模式(Builder Pattern)設計模式UI
- 【設計模式筆記】(二)- Builder模式設計模式筆記UI
- Java設計模式實現之二--策略模式Java設計模式
- 設計模式(五)Builder構建者模式設計模式UI
- 《設計模式》 - 3. 建立者模式( Builder )設計模式UI
- 如何使用充血模型實現防彈程式碼 - DZone Java模型Java
- C#設計模式-建造者模式(Builder Pattern)C#設計模式UI
- 設計模式十: 生成器模式(Builder Pattern)設計模式UI
- 重識設計模式-建造者模式(Builder Pattern)設計模式UI
- 設計模式學習-使用go實現代理模式設計模式Go
- Java併發設計模式--不可變模式(immutable)Java設計模式
- 人人都會設計模式: 07、建造者模式--Builder設計模式UI
- 設計模式學習-使用go實現外觀模式設計模式Go
- 設計模式學習-使用go實現橋接模式設計模式Go橋接
- 設計模式學習-使用go實現建造者模式設計模式Go
- 設計模式學習-使用go實現單例模式設計模式Go單例
- 設計模式學習-使用go實現原型模式設計模式Go原型
- 設計模式學習-使用go實現裝飾模式設計模式Go
- 微服務架構和設計模式 - DZone微服務微服務架構設計模式
- Builder模式與Java語法UI模式Java
- Java設計模式——實現單例模式的七種方式[JZOF]Java設計模式單例
- 設計模式學習-使用go實現觀察者模式設計模式Go
- 設計模式學習-使用go實現介面卡模式設計模式Go
- 設計模式學習-使用go實現訪問者模式設計模式Go
- Java Builder 模式,你搞懂了麼?JavaUI模式
- Java設計模式——模板設計模式Java設計模式
- Go 實現常用設計模式(九)模式Go設計模式
- 設計模式——命令模式實現撤銷設計模式
- 一天一個設計模式(三) - 建造者模式(Builder)設計模式UI
- Java的Void方法是反模式的? - DZoneJava模式