I have two immutable classes: User and Department, they are connected using a bidirectional association - User has a reference to Department and Department has a list of Users. How to create a new Department instance with the provided Users?
Code:
class User {
private final Department department;
private final String name;
public User(Department department, String name) {
this.department = department;
this.name = name;
}
}
class Department {
private final List<User> users;
private final String name;
public Department(List<User> users, String name) {
this.users = new ArrayList<>(users);
this.name = name;
}
}
Immutable class, once an object is instantiated, we cannot modify its content. In Java, all the wrapper classes (let's say, Integer, Short, Boolean, Byte, etc.) and String, etc. classes — are immutable.
I feel in you case you can slightly modify your design and use special UsersBuilder
, i.e.
class Department {
final List<User> users;
final String name;
public Department(String name) {
this.users = UsersBuilder.buildUsers(this);
this.name = name;
}
}
class UsersBuilder {
public static List<User> buildUsers(Department department) {
List<User> usersList = new ArrayList<>();
// add users to the list via department reference
return Collections.unmodifiableList(usersList);
}
}
In general, it is not really good idea to use object's reference before its constructor finishes; but in this particular case it looks safe.
In this case these objects will be really immutable.
You can produce immutable Departments and Users with an extra constructor on Department. From the questions' code, it is inferred that
Since Users are truly just Strings associated to a Department, a Department can be constructed with a List<String>
that represents all User names to be included and use that List<String>
to create a List<User>
within the Department constructor.
Note: what @andremoniy said about letting this
escape from a constructor should not be made a habit of, but it is safe in this case since it is only being passed to a User instance's constructor where that User instance can't be accessed before the Department constructor returns.
Here's what it would look like, in Java 8:
public final class User {
private final Department department;
private final String name;
public User(Department department, String name) {
this.department = department;
this.name = name;
}
public Department getDepartment() {
return department;
}
public String getName() {
return name;
}
}
public final class Department {
private final List<User> users;
private final String name;
///Reversed argument list to avoid collision after erasure
public Department(String name, List<String> users) {
this.users = Collections.unmodifiableList(users.stream()
.map((s) -> new User(this,s)).collect(Collectors.toList()));
this.name = name;
}
public Department(List<User> users, String name) {
this.users = Collections.unmodifiableList(users);
this.name = name;
}
public List<User> getUsers() {
return users;
}
public String getName() {
return name;
}
}
One issue this solution has is that once a Department instance is created, it can be added to new instances of User without the constraint that a new instance of Department be created with an updated List. Consider other abstractions or creational patterns (a full blown Builder implementation where all constructors are private would be a good match here) if you need to support the addition/deletion of users from a Department while maintaining immutability.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With