Абстрагирование от Stateful объекта навигации (1-1) - вызов - PullRequest
0 голосов
/ 01 декабря 2009

Цель этого упражнения - сделать навигацию между объектами с состоянием.

Например, имея Персона и Адрес с ассоциацией 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);

Теперь вопрос: как бы вы абстрагировали код в установщиках, чтобы избежать возможных ошибок при написании большого количества таких классов?

Условия:

  • Интерфейсы PUBLIC классов A и B не могут быть изменены.
  • Фабрики не должны использоваться.
  • Статика не должна использоваться (для сохранения общей информации).
  • ThreadInfo или аналогичное не следует использовать.

1 Ответ

0 голосов
/ 01 декабря 2009

Я действительно не понимаю вашу проблему. Что происходит, когда вы создаете несколько экземпляров класса 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 и B, и не хотите добавлять фабрики в код. Я действительно не вижу последовательного решения при таких ограничениях. Или, может быть, сама задача недостаточно ясна?

РЕДАКТИРОВАТЬ: Делая здесь дикую догадку, я думаю, что то, чего вы пытаетесь достичь здесь, может быть сделано с помощью Reflection: вы можете отразить существующий код до некоторой точки (в стеке вызовов) и сопоставить новый экземпляр скажем, A для существующего экземпляра B. Это можно сделать с помощью отражения, но это довольно сложно, и вы должны иметь конкретный и надежный набор правил для связи между новыми экземплярами A s и B s. Если это является направлением нужного решения, то я думаю, что вам следует погрузиться в отражение и посмотреть, как оно происходит, это огромное поле.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...