patternjavaspringMinor
Circular dependencies between immutable objects; the Freeze Pattern
Viewed 0 times
theobjectsfreezecircularbetweenimmutablepatterndependencies
Problem
Generally, I structure small threadsafe immutable objects like this:
And then wire these up in Spring like this:
However, this leads to complications with circular dependencies. To keep the immutability when this happens, I use a "freeze" pattern, where the variables are set once. This is what I want reviewed:
And then wire them up like this:
public class SmallObject {
private final String state;
public SmallObject(final String state) {
this.state = state;
}
// ...
}And then wire these up in Spring like this:
However, this leads to complications with circular dependencies. To keep the immutability when this happens, I use a "freeze" pattern, where the variables are set once. This is what I want reviewed:
public class SmallObject {
private String state = null;
public void setState(String state) {
if (this.state != null) {
throw new IllegalStateException("state already set: '" + state + "'.");
}
this.state = state;
}
private void ensureInitialized() {
if (this.state == null) {
throw new IllegalStateException(
"state must be set before this instance is used."
);
}
}
// ... For every additional method on the object, I call
// ensureInitialized() first.
}And then wire them up like this:
Solution
This class should instead use an AtomicReference to ensure the state is kept valid. Alternatively, you should incorporate thread-safe handling of the String.
Consider:
This pattern ensures usage is consistent, there can be only one initialization of the instance, and that any thread-unsafe practices are handled well.
Consider:
private final AtomicReference stateref = new AtomicReference();
public void setState(final String state) {
// only one initializer will succeed (assuming state is not null)...
if (!stateref.compareAndSet(null, state)) {
throw new IllegalStateException("state already set: '" + state + "'.");
}
}
private void ensureInitialized() {
if (stateref.get() == null) {
throw new IllegalStateException(
"state must be set before this instance is used."
);
}
}This pattern ensures usage is consistent, there can be only one initialization of the instance, and that any thread-unsafe practices are handled well.
Code Snippets
private final AtomicReference<String> stateref = new AtomicReference<String>();
public void setState(final String state) {
// only one initializer will succeed (assuming state is not null)...
if (!stateref.compareAndSet(null, state)) {
throw new IllegalStateException("state already set: '" + state + "'.");
}
}
private void ensureInitialized() {
if (stateref.get() == null) {
throw new IllegalStateException(
"state must be set before this instance is used."
);
}
}Context
StackExchange Code Review Q#20163, answer score: 7
Revisions (0)
No revisions yet.