But since I started using scala, I realized the value of having immutable objects in your code base.
Immutable objects greatly simplify your program, since they :
- are simple to construct, test, and use
- are automatically thread-safe and have no synchronization issues
- do not need a copy constructor
- do not need an implementation of clone
- allow hashCode to use lazy initialization, and to cache its return value
- do not need to be copied defensively when used as a field
- make good Map keys and Set elements (these objects must not change state while in the collection)
- have their class invariant established once upon construction, and it never needs to be checked again
- always have "failure atomicity" (a term used by Joshua Bloch) : if an immutable object throws an exception, it's never left in an undesirable or indeterminate state
public final class User { private final String name; private final String username; private final String password; private final int permission; private int hashCode; public User(String name, String username, String password, int permission) { this.name = name; this.username = username; this.password = password; this.permission = permission; } public String getName() { return name; } public String getUsername() { return username; } public String getPassword() { return password; } public int getPermission() { return permission; } @Override public int hashCode() {
//This is Lazily loading.
if (hashCode == 0) { int result = name.hashCode(); result = 31 * result + username.hashCode(); result = 31 * result + password.hashCode(); result = 31 * result + permission; hashCode = result; } return hashCode; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; if (permission != user.permission) return false; if (!name.equals(user.name)) return false; if (!password.equals(user.password)) return false; if (!username.equals(user.username)) return false; return true; } }
But what if you have more than 4 fields? It is not going to be pretty having a constructor with more than 4 parameters.
In that case, you can add a Builder.
public final class User { private final String name; private final String username; private final String password; private final int permission; private final Date createDate; private final Date updateDate; private int hashCode; private User(Builder builder) { this.name = builder.name; this.username = builder.username; this.password = builder.password; this.permission = builder.permission; this.createDate = builder.createDate; this.updateDate = builder.updateDate; } public String getName() { return name; } public String getUsername() { return username; } public String getPassword() { return password; } public int getPermission() { return permission; } public Date getCreateDate() { return createDate; } public Date getUpdateDate() { return updateDate; } //equals and hashCode are ommitted. //User Builder public static class Builder { private String name; private String username; private String password; private int permission; private Date createDate; private Date updateDate; public Builder(String username, String password) { this.username = username; this.password = password; } public Builder(User user) { this.name = user.getName(); this.username = user.getUsername(); this.password = user.getPassword(); this.permission = user.getPermission(); this.createDate = user.getCreateDate(); this.updateDate = user.getUpdateDate(); } public Builder setName(String name) { this.name = name; return this; } public Builder setUsername(String username) { this.username = username; return this; } public Builder setPassword(String password) { this.password = password; return this; } public Builder setPermission(int permission) { this.permission = permission; return this; } public Builder setCreateDate(Date createDate) { this.createDate = createDate; return this; } public Builder setUpdateDate(Date updateDate) { this.updateDate = updateDate; return this; } public User build() { return new User(this); } } }
This is how you use it:
User user = new User.Builder("username","pasword").setCreateDate(new Date()).setName("Allan").setPermission(1).build(); //to change the name user = new User.Builder(user).setName("Homer").build(); //change password user = new User.Builder(user).setPassword("secret").build();
Now what happened, if you wanna use immutable Pojo in Hibernate? You can do so, by
- Add @Access annotation in the class level
- Make hashCode transient
Example:
@Entity @Table(name = "system_monitor") @SequenceGenerator(name="PK",sequenceName="system_monitor_id_SEQ") @Access(AccessType.FIELD) public class SystemMonitor { @Id @Column(name = "id", unique = true, nullable = false) @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="PK") private Long id;
...
This looks cool, but it requires a lot of coding. I agree with you. This is why I created this ImmutablePojoGenerator, to help you generate the code. You download the app here - immutablePojoGenerator
No comments:
Post a Comment