从有状态对象导航(1-1)中提取 - 挑战

时间:2009-12-01 04:49:01

标签: c# .net oop

本练习的目的是使对象之间的导航有状态。

例如,拥有1-1关联的人员和地址应该:

  • 如果某人已分配地址,则应将该人员分配到该地址(反之亦然)。
  • 如果地址分配给person1,然后分配给person2,那么person1将没有地址,person2将没有。

这是实现它的一段代码。

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;
        }
    }
}

这允许以下测试通过:

// 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);

现在的问题是:如何在编写器中抽象代码以避免在编写大量此类时可能出现的错误?

条件是:

  • 无法更改A类和B类的PUBLIC接口。
  • 不应使用工厂。
  • 不应使用静态(保留共享信息)。
  • 不应使用ThreadInfo或类似内容。

1 个答案:

答案 0 :(得分:0)

我真的不明白你的挑战。当您实例化A类的几个实例然后实例化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();

哪个测试合格?哪一个失败了?

您会看到,实例化A后,它会有状态。此状态应以某种方式涉及B的实例,现有实例。因此,即使在实例化此B类之前,此A实例也必须存在。

B的实例也是如此。它应该包含对已存在的A实例的引用。

据我了解,A类应该有一个构造函数,引用现有的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

使用B或其他方式使用A

您写道,您不想更改BA的公共签名,并且您不希望在代码中添加工厂。在这种限制下我真的看不到一致的解决方案。或者挑战本身还不够明确?

编辑:在这里做一个疯狂的猜测,我认为你在这里尝试实现的目标可以使用Reflection完成:你可能希望将现有代码反映到某一点(在调用堆栈中),并匹配一个新的实例,例如,BA的现有实例。这可以可以使用反射来完成,但这很难,你必须有一套具体而强大的规则来实现B和{{1}} s的新实例之间的联系。 。如果 是所需解决方案的方向,那么我认为你应该深入思考并看看它是如何发展的,这是一个巨大的领域。