内容简介:Effective Java的一条建议是,除非有充分的理由让它们变得可变,否则你应该让你的类不可变。如果一个类不能成为不可变的,那么尽可能地限制它的可变性。不可变类定义了一旦创建,就永远不会改变其状态的对象。所有状态信息都是在构造对象时提供的,并且在对象的生命周期内不会改变。不可变类提供了许多优于可变类的优点。这些是:
Effective Java的一条建议是,除非有充分的理由让它们变得可变,否则你应该让你的类不可变。如果一个类不能成为不可变的,那么尽可能地限制它的可变性。不可变类定义了一旦创建,就永远不会改变其状态的对象。所有状态信息都是在构造对象时提供的,并且在对象的生命周期内不会改变。
我们为什么要编写不可变类?
不可变类提供了许多优于可变类的优点。这些是:
- 不可变对象简单易用,因为它只能处于一个状态,即创建它的状态。
- 它们本质上是线程安全的,即它们不需要同步。
- 不可变类的对象可以自由共享。例如,Boolean类重用其现有实例TRUE和FALSE,每当调用Boolean.valueOf方法时,它都会为您提供已创建的实例。
创建一个不可变类
一个简单的不可变类可以是这样的:
<b>public</b> <b>final</b> <b>class</b> User {
<b>private</b> <b>final</b> String username;
<b>private</b> <b>final</b> String password;
<b>public</b> User(String username, String password) {
<b>this</b>.username = username;
<b>this</b>.password = password;
}
<b>public</b> String getUsername() {
<b>return</b> username;
}
<b>public</b> String getPassword() {
<b>return</b> password;
}
}
这个类是不可变的,因为:
- 它不提供setter方法或mutator。
- Class不能扩展,因为它是最终的。这也可以通过使构造函数私有来完成。
- class的字段都是最终的和私人的。
值得注意的是,这个类非常简单,只有两个字段。在我们的实际应用程序的大多数类中,有两个以上的字段。此外,大多数这些字段对于对象创建不是必需的。例如,真实应用程序中的用户将具有用户名,密码,名字,姓氏,creationDate,emailAddress等,但是对于此处的用户创建,仅需要用户名和密码。所以,我们设计我们的类如下所示:
<b>final</b> <b>class</b> User {
<b>private</b> <b>final</b> String username;
<b>private</b> <b>final</b> String password;
<b>private</b> String firstname;
<b>private</b> String lastname;
<b>private</b> String email;
<b>private</b> Date creationDate;
<b>public</b> User(String username, String password) {
<b>this</b>.username = username;
<b>this</b>.password = password;
creationDate = <b>new</b> Date();
}
<b>public</b> String getUsername() {
<b>return</b> username;
}
<b>public</b> String getPassword() {
<b>return</b> password;
}
<b>public</b> String getFirstname() {
<b>return</b> firstname;
}
<b>public</b> <b>void</b> setFirstname(String firstname) {
<b>this</b>.firstname = firstname;
}
<b>public</b> String getLastname() {
<b>return</b> lastname;
}
<b>public</b> <b>void</b> setLastname(String lastname) {
<b>this</b>.lastname = lastname;
}
<b>public</b> String getEmail() {
<b>return</b> email;
}
<b>public</b> <b>void</b> setEmail(String email) {
<b>this</b>.email = email;
}
<b>public</b> Date getCreationDate() {
<b>return</b> <b>new</b> Date(creationDate.getTime());
}
}
这个类不是不可变的,因为它有mutators,即setter。因此,可以在创建后修改此类的实例。这种方法的缺点是,对象可能处于不一致的状态,通过它们的构造方式,你必须付出额外的努力来确保线程安全。
Builder Design Pattern来救援
据Gof说:
构建器模式将复杂对象的构造与其表示分开,以便相同的构造过程可以创建不同的表示。
构建器 设计模式 为您提供了构建复杂不可变对象的方法。过程是:
- 客户端使用所有必需参数调用构造函数(或静态工厂)并获取构建器对象。
- 客户端调用setter之类的方法来设置每个感兴趣的可选参数。
- 最后,客户端调用构建方法来生成不可变的对象。
不可变的用户:
<b>public</b> <b>class</b> ImmutableUser {
<b>private</b> <b>final</b> String username;
<b>private</b> <b>final</b> String password;
<b>private</b> <b>final</b> String firstname;
<b>private</b> <b>final</b> String lastname;
<b>private</b> <b>final</b> String email;
<b>private</b> <b>final</b> Date creationDate;
<b>private</b> ImmutableUser(UserBuilder builder) {
<b>this</b>.username = builder.username;
<b>this</b>.password = builder.password;
<b>this</b>.creationDate = builder.creationDate;
<b>this</b>.firstname = builder.firstname;
<b>this</b>.lastname = builder.lastname;
<b>this</b>.email = builder.email;
}
<b>public</b> String getUsername() {
<b>return</b> username;
}
<b>public</b> String getPassword() {
<b>return</b> password;
}
<b>public</b> String getFirstname() {
<b>return</b> firstname;
}
<b>public</b> String getLastname() {
<b>return</b> lastname;
}
<b>public</b> String getEmail() {
<b>return</b> email;
}
<b>public</b> Date getCreationDate() {
<b>return</b> <b>new</b> Date(creationDate.getTime());
}
<b>public</b> <b>static</b> <b>class</b> UserBuilder {
<b>private</b> <b>final</b> String username;
<b>private</b> <b>final</b> String password;
<b>private</b> <b>final</b> Date creationDate;
<b>private</b> String firstname;
<b>private</b> String lastname;
<b>private</b> String email;
<b>public</b> UserBuilder(String username, String password) {
<b>this</b>.username = username;
<b>this</b>.password = password;
<b>this</b>.creationDate = <b>new</b> Date();
}
<b>public</b> UserBuilder firstName(String firsname) {
<b>this</b>.firstname = firsname;
<b>return</b> <b>this</b>;
}
<b>public</b> UserBuilder lastName(String lastname) {
<b>this</b>.lastname = lastname;
<b>return</b> <b>this</b>;
}
<b>public</b> UserBuilder email(String email) {
<b>this</b>.email = email;
<b>return</b> <b>this</b>;
}
<b>public</b> ImmutableUser build() {
<b>return</b> <b>new</b> ImmutableUser(<b>this</b>);
}
}
}
您还应检查构建方法中的不变量,如果任何属性无效,则抛出IllegalStateException。这将确保对象在实例化后处于可工作状态。
<b>public</b> <b>static</b> <b>void</b> main(String[] args) {
ImmutableUser user = <b>new</b> ImmutableUser.UserBuilder(<font>"shekhar"</font><font>, </font><font>"password"</font><font>).firstName
(</font><font>"shekhar"</font><font>).lastName(</font><font>"gulati"</font><font>).email(</font><font>"shekhargulati84@gmail.com"</font><font>).build();
}
</font>
通过这种方式,您可以构建一个不可变的复杂对象,并具有不可变对象的所有优点。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- [Java并发-17-并发设计模式] Immutability模式:如何利用不变性解决并发问题?
- JavaScript对象不变性知多少
- 【Rust】RefCell和内部可变性
- 《快学 Go 语言》第 14 课 —— 魔术变性指针
- Rust中的RefCell和内部可变性
- python对象引用,可变性和垃圾回收
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。