реализация двунаправленной ассоциации в c #: как можно передать один объект в качестве параметра только один раз в c # - PullRequest
1 голос
/ 11 апреля 2011

Я надеюсь сформулировать мой вопрос правильно (если нет, пожалуйста, помогите мне дать ему лучшее название), чтобы прояснить его, пожалуйста, посмотрите на мой код.


class Factory
{
    public string Name { get; set; }

    private Person _manager;
    public Person Manager 
    {
        get
        {
            return (_manager );
        }
        set
        {
            _manager = value;
            if (_manager.WorkPlace!=this)
            {
                _manager.WorkPlace = this;
            }
        }
    }

    public Factory(string name, Person manager)
    {
        Name = name;
        Manager = manager;
        if (Manager.WorkPlace ==null)
        {
            Manager.WorkPlace = this;
        }

    }

    public Factory(string name, string managerFullName, int managerAge)
    {
        Name = name;
        Manager = new Person(managerFullName, managerAge);

        if (Manager.WorkPlace != this)
        {
            Manager.WorkPlace = this;
        }

    }

    public void ShowInfo()
    {...}

}

появляется моя проблемапри использовании первого конструктора фабричного класса

class Program
{
    static void Main(string[] args)
    {
        Person oPerson1=new Person("Jon",30);

        factory oFactory1=new Factory("f1",oPerson1);
        factory oFactory2=new Factory("f2",oPerson1);
        factory oFactory3=new Factory("f3",oPerson1);
        factory oFactory4=new Factory("f4",oPerson1);
        ...
    }
}

, как вы можете видеть в этом конструкторе , я могу использовать один объект персонажа (в качестве ясеня) более одного раза, фактически много разэто можно использовать, и ничто не мешает мне .это означает, что один человек может управлять многими фабриками, я не хочу этого. Я хочу, чтобы человек мог управлять только одной фабрикой , как это возможно?


чтобы справиться с этой проблемой, мне в голову пришли некоторые обходные пути.1 - удаление этого конструктора и использование только другого. (Но я ищу лучшее решение, я хотел бы иметь этот конструктор.)2 - выдает исключение во время выполнения, которое я ненавижу


, так как я знаю, что компилятору c # нечего не препятствовать передаче объекта более одного разая должен изменить что-то в дизайне класса?какова ваша рекомендация?Какое лучшее решение? Спасибо большое за любые советы.

РЕДАКТИРОВАТЬ: Наша бизнес-логика

на каждом заводе есть менеджер, егобессмысленно иметь фабрику без менеджера.

и человек может быть менеджером.

человек (1..1) ------------ (0..1) завод

Ответы [ 5 ]

3 голосов
/ 11 апреля 2011

Отношения лучше моделируются со статическими отношениями кода, чем с обязательными проверками.Это позволило бы компилятору помочь вам обеспечить соблюдение отношений.

Удалите менеджер с фабрики и добавьте фабрику к менеджеру:

public class Manager : Person
{
    public Manager(Factory factory)
}

Таким образом, менеджер может управлять только однимFactory ...

3 голосов
/ 11 апреля 2011

Ответ в вашем коде:

set
{
    _manager = value;
    if (_manager.WorkPlace!=this)
    {
        _manager.WorkPlace = this;
    }
}

Замените это на

set
{
    if (value == null)  // Edit: Add manager release capability to change factories
    {
        if(_manager != null)
           _manager.WorkPlace = null;

        _manager = null;
    }
    else if (value.WorkPlace == null)
    {
        _manager = value;
        _manager.WorkPlace = this;
    }
    else
        throw new ArgumentException();
}
2 голосов
/ 11 апреля 2011

Я использую следующий «микропаттерн» для сеттеров:

    public Person Manager 
    {
        get
        {
            return (_manager );
        }
        set
        {
            if (_manager != null)
            {
                _manager.WorkPlace = null;
            }

            _manager = value;

            if (_manager != null)
            {
                _manager.WorkPlace = this;
            }
        }

Теперь, когда вы связываете менеджера с фабрикой, его старый менеджер автоматически де-ассоциируется с фабрикой.

Теперь это не мешает вам переназначить менеджера на завод. Но это гарантирует, что указатели всегда синхронизированы друг с другом.

Я узнал этот трюк от Рефакторинга Мартина Фаулера. Онлайн-ссылку на технику можно найти здесь .

1 голос
/ 06 ноября 2015

«Ячейка» имеет «Предмет»;и «Предмет» имеет «Ячейку».Если вы обновите один из них;другой также должен быть обновлен.Таким образом, в ячейке у нас есть свойство как:

    public Item CurrentItem
    {
        get { return _currentItem; }
        set
        {
            if (_currentItem == value) return;
            var oldItem = _currentItem;
            _currentItem = value;
            if (oldItem != null && oldItem.CurrentCell == this)
            {
                oldItem.CurrentCell = null;
            }
            if (value != null)
            {
                value.CurrentCell = this;
            }
        }
    }

На противоположном сайте (в элементе) у нас есть следующее свойство:

    public Cell CurrentCell
    {
        get { return _currentCell; }
        set
        {
            if (_currentCell == value) return;
            var oldCell = _currentCell;
            _currentCell = value;
            if (oldCell != null && oldCell.CurrentItem == this)
            {
                oldCell.CurrentItem = null;
            }
            if (value != null)
            {
                value.CurrentItem = this;
            }
        }
    }
1 голос
/ 11 апреля 2011

Несмотря на то, что вы ненавидите это, создание исключения в конструкторе предупредит вас заранее, что у вас есть ошибка. Вы также должны убедиться, что Человек не является менеджером.

public Factory(string name, Person manager)
{   if (Manager.WorkPlace != null && Manager.WorkPlace.Manager==manager)
    { 
        var errmsg = "Cannot pass an existing manager to Factory constructor.";
        throw new ArgumentException("manager",errmsg);
    }

    Name = name;
    Manager = manager;
    Manager.WorkPlace = this;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...