Immutable cyclic graph with dependency injection

P

Philipp

Hello,
I have a structure with two classes, let's call them Car and
SteeringWheel for the example.
Car /owns/ a SteeringWheel: in production code, the lifetime of the
SteeringWheel is directly dependent on the lifetime of the Car.
In my design, the SteeringWheel object needs a reference to the Car
object (let's say, to transmit when the user honks). I see several
ways to build and initialize this class-graph, but none so far that I
think perfect.

What is the best way to create and initialise that structure?

A few of my previous ideas are:
1) Build graph dependency in constructor:
public class Car {
private final SteeringWheel wheel;
public Car() {
wheel = new SteeringWheel(this);
}
}
public class SteeringWheel {
private final Car car;
public SteeringWheel(Car car) {
this.car = car;
}
}

Cons: a) /this/ pointer leaks in constructor b) Car is not unit-
testable without SteeringWheel

2) Use a setter and a static factory
public class Car {
private SteeringWheel wheel;
public void setWheel(SteeringWheel wheel) {
this.wheel = wheel;
}
public static Car newInstance(){
Car c = new Car();
SteeringWheel s = new SteeringWheel(c);
c.setWheel(s);
return c;
}
}
public class SteeringWheel {
private final Car car;
public SteeringWheel(Car car) {
this.car = car;
}
}
Cons: a) field /wheel/ in Car cannot be made final (I like
immutability) b) I must always check if wheel was correctly set as
nothing enforces the correct construction sequence

3) The JavaBean way:
public class Car {
private SteeringWheel wheel;
public void setWheel(SteeringWheel wheel) {
this.wheel = wheel;
}
public static Car newInstance(){
Car c = new Car();
SteeringWheel s = new SteeringWheel();
c.setWheel(s);
s.setCar(c);
return c;
}
}
public class SteeringWheel {
private Car car;
public void setCar(Car car) {
this.car = car;
}
}

Cons: Same problems as 2, but with added insecurity

Are there constructs to build that graph which bundle all advantages?
ie. testable through dependency injection, immutable (for thread
safety) and guaranteing the invariants (example: wheel is not null)

Thanks for your answers
Philipp
 
D

Donkey Hottie

Philipp said:
Hello,
I have a structure with two classes, let's call them Car
and SteeringWheel for the example.
Car /owns/ a SteeringWheel: in production code, the
lifetime of the SteeringWheel is directly dependent on
the lifetime of the Car.
In my design, the SteeringWheel object needs a reference
to the Car object (let's say, to transmit when the user
honks). I see several ways to build and initialize this
class-graph, but none so far that I think perfect.

What is the best way to create and initialise that
structure?

A few of my previous ideas are:
1) Build graph dependency in constructor:
public class Car {
private final SteeringWheel wheel;
public Car() {
wheel = new SteeringWheel(this);
}
}
public class SteeringWheel {
private final Car car;
public SteeringWheel(Car car) {
this.car = car;
}
}

Cons: a) /this/ pointer leaks in constructor b) Car is
not unit- testable without SteeringWheel

2) Use a setter and a static factory
public class Car {
private SteeringWheel wheel;
public void setWheel(SteeringWheel wheel) {
this.wheel = wheel;
}
public static Car newInstance(){
Car c = new Car();
SteeringWheel s = new SteeringWheel(c);
c.setWheel(s);
return c;
}
}
public class SteeringWheel {
private final Car car;
public SteeringWheel(Car car) {
this.car = car;
}
}
Cons: a) field /wheel/ in Car cannot be made final (I like
immutability) b) I must always check if wheel was
correctly set as nothing enforces the correct
construction sequence

3) The JavaBean way:
public class Car {
private SteeringWheel wheel;
public void setWheel(SteeringWheel wheel) {
this.wheel = wheel;
}
public static Car newInstance(){
Car c = new Car();
SteeringWheel s = new SteeringWheel();
c.setWheel(s);
s.setCar(c);
return c;
}
}
public class SteeringWheel {
private Car car;
public void setCar(Car car) {
this.car = car;
}
}

Cons: Same problems as 2, but with added insecurity

Are there constructs to build that graph which bundle all
advantages? ie. testable through dependency injection,
immutable (for thread safety) and guaranteing the
invariants (example: wheel is not null)

I have changed the steering wheel in my car, more that once. During the
process, the steering wheel property of my car was definitely null. The car
was absulute useless during that time, and it threw an Exception if it was
tried to drive with. Starting the engine is no problem, but steering it was
pain.
 
P

Philipp

The steering wheel doesn't necessarily need a reference to the car. It
can fire an event of honk, and the car would have a listener for it. I
think this is the observer pattern (I'm not good with names).

This is basically the setter method. Having an addHonkListener
(HonkListener) in SteeringWheel instead of a setCar(Car) is really the
same thing. It is certainly good to use interfaces (Car implements
HonkListener), and using a Collection internally gets rid of the null
check.

private void sendHonk(){
if(car != null){
car.honk();
}
}

is replaced by
private void sendHonk(){
for(Iterator it = honkListeners.iterator(); it.hasNext();){
HonkListener hl = (HonkListener)it.next();
hl.honk();
}
}

But I do not get thread safety: adding an additional honk listener to
the steering wheel may or may not be seen by another thread.

Phil
 
P

Philipp

I have changed the steering wheel in my car, more that once. During the
process, the steering wheel property of my car was definitely null. The car
was absulute useless during that time, and it threw an Exception if it was
tried to drive with. Starting the engine is no problem, but steering it was
pain.

Funny :)

You mean: instead of enforcing invariants, throw exception if they are
not met?
Not sure that this is a good idea. But maybe there is no better way...

Phil
 
D

Donkey Hottie

Philipp said:
Funny :)

You mean: instead of enforcing invariants, throw
exception if they are not met?
Not sure that this is a good idea. But maybe there is no
better way...

If you do not want NullPointerException you have to implement some kind of
checkList() throws CheckListException.

That's what the do in airplanes before they steer them.

With cars, it usually goes with the NPE..
 
O

Owen Jacobson

Hello,
I have a structure with two classes, let's call them Car and
SteeringWheel for the example.
Car /owns/ a SteeringWheel: in production code, the lifetime of the
SteeringWheel is directly dependent on the lifetime of the Car.
In my design, the SteeringWheel object needs a reference to the Car
object (let's say, to transmit when the user honks).

This kind of designed-in circularity is usually a flaw. I'd be inclined
to move the logic that's in Car that needs to be shared with
SteeringWheel into its own object, which both Car and SteeringWheel
have a reference to. If only SteeringWheel is actually using that bit
of logic, I might even move it into SteeringWheel itself.

I see several
ways to build and initialize this class-graph, but none so far that I
think perfect.

If you take a strict view of immutability, you can't initialize an
immutable, circular structure. You need to introduce some formal
mutability somewhere, even if the result behaves as if it were
immutable. Alternately, break the circular references.

If you're using setters to make something mutable, you have the option
of making the setter package-visible to restrict it to code that
"should" have access to it. You can also use a post-property
initialization method: Spring calls it "afterPropertiesSet()" (it's
optional, and you can define your own with annotations), which is
called automatically to validate the properties of an object and
establish initial state when setter injection is in use (eg. throughout
the Spring libraries). You can emulate this kind of behaviour without
using a DI container, but it's somewhat less transparent.

-o
 
M

markspace

Philipp said:
But I do not get thread safety: adding an additional honk listener to
the steering wheel may or may not be seen by another thread.


Needs synchronization then.

Use CopyOnWriteArrayList if you have a recent version of Java. Use
Collections.synchronizedList( List ) if you need to support older Java
installations.
 
T

Tom Anderson

If you take a strict view of immutability, you can't initialize an
immutable, circular structure. You need to introduce some formal
mutability somewhere, even if the result behaves as if it were
immutable.

Whilst i wouldn't call this strict, or a good idea (seriously - not *at
all*), you *can* change final references after construction - you can do
it with sun.misc.Unsafe. But of course, that's not a feature of java :).

tom
 
O

Owen Jacobson

Whilst i wouldn't call this strict, or a good idea (seriously - not *at
all*), you *can* change final references after construction - you can
do it with sun.misc.Unsafe. But of course, that's not a feature of java
:).

Once upon a time, the JVM itself treated final identifiers like any
other identifier in the same category, and allowed bytecode that
directly modified final locals, fields, etc.. javac makes assumptions
about final fields (by inlining constant expressions) that rely on that
never happening.

I have no idea, nor do I want to know, if that's still true.

-o
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top