Abstracting from Stateful object navigation (1-1) - the challenge
The point of this exercise is to make navigation between objects stateful.
For example, having Person and Address with 1-1 association it should:
- If an address is assigned to a persons, then the person should be assigned to the address (and vice versa).
- If address is assigned to person1 and then to person2, then the person1 will have no address and person2 will.
This is the piece of code that implements it.
public class A {
开发者_运维技巧 internal B a;
public B Value {
get {
return a;
}
set {
if (value == null) {
if (a != null)
a.a = null;
} else
value.a = this;
a = value;
}
}
}
public class B {
internal A a;
public A Value {
get {
return a;
}
set {
if (value == null) {
if (a != null)
a.a = null;
} else
value.a = this;
a = value;
}
}
}
This allows following tests to pass:
// For the common setup:
var a = new A();
var b = new B();
// Test 1:
a.Value = b;
Assert.AreSame(a, b.Value);
// Test 2:
b.Value = a;
Assert.AreEqual(b, a.Value);
// Test 3:
b.Value = a;
b.Value = null;
Assert.IsNull(a.Value);
// Test 4:
var a2 = new A();
b.Value = a2;
Assert.AreSame(b, a2.Value);
Assert.AreNotSame(a, b.Value);
// Test 5:
a.Value = b;
Assert.AreSame(a, b.Value);
var a1 = new A();
var b1 = new B();
a1.Value = b1;
Assert.AreSame(a1, b1.Value);
// Test 6:
var a1 = new A();
var b1 = new B();
Assert.IsNull(a.Value);
Assert.IsNull(b.Value);
Assert.IsNull(a1.Value);
Assert.IsNull(b1.Value);
Now the question is: how would you abstract the code in the setters to avoid possible mistakes when writing a lot of such classes?
The conditions are:
- The PUBLIC interfaces of classes A and B cannot be changed.
- Factories should not be used.
- Statics should not be used (to persist shared info).
- ThreadInfo or similar should not be used.
I really don't understand your challenge. What happens when you instantiate a few instances of class A and then a single instance of class B?
A a1 = new A();
A a2 = new A();
A a3 = new A();
A a4 = new A();
A a5 = new A();
B b = new B();
Which test passes? Which one fails?
You see, once A
is instantiated, it has a state. This state should be somehow involved with an instance of B
, an existing instance. So this instance of B
must exist even before you instantiate this A
class.
The same is true for an instance of B
. It should hold a reference to an already existing instance of A
.
As far as I understand, class A should have a constructor with a reference to an existing instance of B:
public class A
{
private B b;
public A(B b)
{
this.b = b;
}
}
// Then you can have:
B b1 = new B();
A a1 = new A(b1); // here's the link
B b2 = new B();
A a2 = new A(b2); // and another link
Either this or the other way around with B
.
You write that you don't want to change the public signatures of A
and B
, and you don't want to add factories to the code. I really can't see a consistent solution under such constraints. Or maybe the challenge itself is not clear enough?
EDIT: Taking a wild guess here, I think that what you try to achieve here can be done using Reflection: you might want to reflect existing code up to a point (in the call stack), and match a new instance of, say, A
to an existing instance of B
. This is can be done using reflection, but it's pretty hard and you must have a concrete and robust set of rules for the linkage between new instances of A
s and B
s. If this is the direction of the needed solution, then I think you should dive into reflection and see how it goes, it's a huge field.
精彩评论