Боксер наилегчайшего веса и проблема Фабрики с IDisposable

Я, кажется, мысленно застреваю в дилемме шаблона В наилегчайшем весе.

Во-первых, скажем, у меня есть доступный тип DisposableFiddle и фабрика FiddleFactory:

public interface DisposableFiddle : IDisposable
{
    // Implements IDisposable
}

public class FiddleFactory
{
    public DisposableFiddle CreateFiddle(SomethingThatDifferentiatesFiddles s)
    {
        // returns a newly created fiddle.
    }
}

Затем по-моему, это довольно ясно клиенту FiddleFactory то, что фабрика не требует никакого владения созданной скрипки и что это - обязанность клиента расположить скрипку при выполнении с нею.

Однако давайте вместо этого скажем, что я хочу совместно использовать скрипки между клиентами при помощи шаблона В наилегчайшем весе:

public class FiddleFactory
{
    private Dictionary<SomethingThatDifferentiatesFiddles, DisposableFiddle> fiddles = new ...;        

    public DisposableFiddle CreateFiddle(SomethingThatDifferentiatesFiddles s)
    {
        // returns an existing fiddle if a corresponding s is found,
        // or a newly created fiddle, after adding it to the dictionary,
        // if no corresponding s is found.
    }
}

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

Проблема на самом деле, что я называю фабрику FiddleFactory вместо, скажем, FiddlePool, и метод "создания" CreateFiddle вместо GetFiddle? Как это:

public class FiddlePool : IDisposable
{
    private Dictionary<SomethingThatDifferentiatesFiddles, DisposableFiddle> fiddles = new ...;        

    public DisposableFiddle GetFiddle(SomethingThatDifferentiatesFiddles s)
    {
        // returns an existing fiddle if a corresponding s is found,
        // or a newly created fiddle, after adding it to the dictionary,
        // if no corresponding s is found.
    }

    // Implements IDisposable
}

Тогда клиенту более ясно, что это не будет владеть возвращенной скрипкой, и это - обязанность пула расположить скрипки.

Или это может только быть с готовностью решено мудрое документацией?

Существует ли выход из дилеммы? Существует ли даже дилемма?:-)

11
задан Johann Gerell 25 February 2010 в 17:34
поделиться

3 ответа

Существует 3 типа указателей const:

//Data that p points to cannot be changed from p
const char* p = szBuffer;

//p cannot point to something different.  
char* const p = szBuffer;

//Both of the above restrictions apply on p
const char* const p = szBuffer;

Метод # 2 выше наиболее похож на ссылку.

Существуют ключевые различия между ссылками и указателями const всех 3 типов:

-121--1227378-

Я предполагаю, что вы имеете в виду указатель на конст (например, int * const ptr), а не указатель на конст (например, int const * ptr).

  • Не инициализация ссылки является ошибкой компиляции (избегает проблемы неинициализированных указателей)
  • Указатель может также указывать на массив, или он может иметь значение NULL, где ссылка всегда ссылается только на один объект.
  • Синтаксис очень отличается
-121--1227379-

Я вижу два выхода из этой проблемы:

  • ThreadPool-style : перепроектировать классы, чтобы FidingPool обеспечивал интерфейс для точного выполнения задач. Пул не выдает экземпляры Fiddle , поскольку вместо них используется метод FidingPool.PlayFiddle . Так как пул контролирует время жизни, он отвечает за их утилизацию.

  • SqlConnection-style : изменение метода открытого удаления Fiddle так, что он действительно просто возвращает fiddle в пул fiddle (который инкапсулирует класс fiddle). Внутри пула fiddle заботится о действительно высвобождении одноразовых ресурсов.

7
ответ дан 3 December 2019 в 10:03
поделиться

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

База данных объединяет множество соединений, которые сами поддерживают пул. Вызывающий код создает соединение, открывает его и вызывает для него close (dispose). Вызывающий код даже не знает, объединен ли он в пул или нет, все это обрабатывается внутри класса соединения. При объединенном соединении вызов Open () игнорируется, если соединение уже открыто. Вызывается Close () / Dispose (), и в случае объединения в пул это фактически возвращает соединение обратно в пул, а не закрывает его.

Вы можете сделать то же самое, создав класс PooledFiddle, который переопределяет Dispose и возвращает объект в пул. В идеале клиенту даже не нужно было бы знать, что это объединенная скрипка.

1
ответ дан 3 December 2019 в 10:03
поделиться

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

2
ответ дан 3 December 2019 в 10:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: