Какое имя лучше для оболочки, которая обеспечивает потоковое добавление, удаление, итерацию по коллекции для различных объектов? - PullRequest
2 голосов
/ 26 февраля 2010

Это немного странный сценарий. У меня был класс, который быстро становился классом Бога. Это делало слишком много. Внезапно я нарушил СРП. Класс отвечал за X и Y и Z, о и A, и B, не забывайте C. Так что я решил реорганизовать его. Причина, по которой он стал таким большим, заключается в том, что класс выполняет большую работу с коллекцией, и я проделал большую работу по синхронизации доступа к ней, поскольку это многопоточная система, использующая ReaderWriterLockSlim.

Итак, я определил основные обязанности. Есть часть, которая кормит коллекцию. Иногда может потребоваться сделать новый элемент в коллекции. У меня есть объект, который очищает коллекцию по таймеру. Поэтому, когда таймер истекает, я ищу элементы, которые можно удалить из коллекции. Тогда у меня есть объект, который должен извлечь вещи из коллекции. Он должен запросить каждый элемент в коллекции, поэтому он должен повторяться.

Ранее объект делал все это сам. Прост в управлении с точки зрения блокировки. Не так легко провести юнит-тест. Слишком много всего происходит, слишком много насмешек. Это было просто противно. Разбиение его на части значительно облегчает тестирование модулей, НО значительно усложняет блокировку.

Таким образом, каждая часть, устройство подачи, очиститель и ретривер должны иметь экземпляр этого объекта. Так что я должен вставить его в конструктор, а затем я могу его смоделировать, и тестирование легко. Но теперь, поскольку коллекция является общей для многих объектов, я не могу предоставить каждому прямой доступ к ней. Мне нужно предоставить своего рода оболочку синхронизации.

Я думал, что, когда устройство подачи запрашивает новый элемент в коллекции, упаковщик блокирует коллекцию, создает новый элемент, передает его устройству подачи и уведомляет уборщика о наличии нового элемента в коллекции. Уборщик добавляет этот предмет в свою копию коллекции.

Когда уборщик запускается, он просматривает свою версию коллекции, когда он находит что-то, что может быть удалено, он удаляет его из своей коллекции и информирует обертку, а обертка уведомляет устройство подачи, которое вынимает ее из своей коллекции. Ретривер использует цикл foreach. Таким образом, оболочка может реализовывать IEnumerator и IDispose. Затем, когда счетчик создан, я могу заблокировать коллекцию, а когда он удаляется, я могу выйти из блокировки.

  1. Есть ли шаблон дизайна для того, что я пытаюсь сделать?
  2. Есть ли лучший способ сделать это?
  3. Какое хорошее название для этой обертки?

Я подумал о следующем:

  • Провайдер (но это больше, чем просто предоставление)
  • Maintainer (немного расплывчато)
  • Синхронизатор (мне этот нравится больше всего)

Ответы [ 3 ]

2 голосов
/ 26 февраля 2010

Я думаю, что ваша идея с провайдером, сопровождающим и синхронизатором звучит очень хорошо ... Я не знаю о шаблонном паттерне для этой ситуации, так что ваш кажется разумным.

Теперь часть, в которой, как мне кажется, я могу вам помочь, - это итерация. Прежде всего, вам нужно будет создать обертку для вашей коллекции. Оболочка просто обернет все стандартные методы коллекции. Например:

public void Add(Object obj)
{
    lock(sync)
    {
        _collection.Add(obj);
    }
}

Во-вторых, если вы хотите заблокировать счетчик, вы следуете в этом примере .

Мне не нравится идея позволить сборщику мусора решать, когда разблокировать объект синхронизации, поэтому, по моему личному мнению, я бы предпочел сделать это оптимистичным способом:
1. Скопируйте каждый элемент коллекции в новую коллекцию.
2. Верните этот перечислитель новой коллекции.
3. При переборе перечислителя делайте все мои модификации в исходной коллекции.

Вот пример:

// In your Collection wrapper you need to provide an enumerable copy:
public IEnumerator<T> GetEnumerator()
{
    lock(sync)
    {
        Collection copy = new Collection():
        foreach(Object element in collection)
        {
            copy.Add(element);
        }

        return copy.GetEnumerator();
    }
}


// In your Maintainer's cleanup method you will do the following:
public void TimedCleanup()
{

    // You don't have any contention on the original collection.
    foreach(Object element in originalCollection)
    {
        if(shouldDeleteElement)
        {
            // Not a problem if somebody already iterated over
            // the collection and removed the same element.     
            originalColection.Remove(element);
        }
    }
}

Надеюсь, это ответит на ваш вопрос:).

1 голос
/ 26 февраля 2010

Ваши потребители действительно должны работать с живыми данными? Вы можете просто предоставить им копию коллекции, чтобы они могли свободно перебирать без какой-либо блокировки. Я бы также предложил использовать события для синхронизации. Может быть, даже агрегатор событий?

0 голосов
/ 04 марта 2010

Еще одна вещь, которую следует учитывать - это параллельные коллекции в параллельных расширениях ...

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