2009-09-17 4 views
2

Отложив до сих пор аргументы относительно относительных добродетелей и disvirtues шаблона Singleton и учитывая, что Singleton обычно считается экземпляром, который сохраняется на протяжении всего срока службы приложения, что было бы лучшим способом иметь синглтон, который имеет ограниченную жизнь?Истекает экземпляр Singleton после периода времени

Есть ли что-нибудь неладно что-то вроде следующего:

public class CategoryHandler 
{  

    private static DateTime m_expires; 

    public bool HasExpired 
    { 
     get return DateTime.Now > m_expires; 
    } 

    private CategoryHandler() 
    { 
     m_expires = DateTime.Now.AddMinutes(60); 
    } 

    public static CategoryHandler Instance() 
    { 
     if(HasExpired) 
     { 
      //Dispose and reconstruct 
     } 
     else 
     { 
      //Use existing instance 
     } 
    } 

} 

Или есть гораздо лучший способ подойти к этой проблеме?

+3

Вам нужно пропустить синглтон, удалив его через 60 минут или просто «в следующий раз, когда кто-то использует его через 60 минут»? –

+0

Это будет в следующий раз, когда он будет использован через 60 минут (или, как бы долго он ни был, я выбрал 60 минут только для примера). – Jason

ответ

3

Вам нужно какое-то блокировка, чтобы обеспечить безопасность потоков:

public sealed class CategoryHandler 
{ 
    private static CategoryHandler _instance = null; 
    private static DateTime _expiry = DateTime.MinValue; 
    private static readonly object _lock = new object(); 

    private CategoryHandler() { } 

    public static bool HasExpired 
    { 
     get 
     { 
      lock (_lock) { return (_expiry < DateTime.Now); } 
     } 
    } 

    public static CategoryHandler Instance 
    { 
     get 
     { 
      lock (_lock) 
      { 
       if (HasExpired) 
       { 
        // dispose and reconstruct _instance 
        _expiry = DateTime.Now.AddMinutes(60); 
       } 
       return _instance; 
      } 
     } 
    } 
} 
+0

Действительно, я знаю, я знаком с этим. Я думаю, может быть, я упростил код exmaple! – Jason

2

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

CategoryHandler.Instance.Method(); 

вместо

CategoryHandler singleton = CategoryHandler.Instance; 
... 
singleton.SomeMethod(); 

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

Если вам нужно, чтобы он истекал через определенный период времени, вам нужно будет использовать таймер и заменить экземпляр в методе обратного вызова (остерегайтесь, что таймер будет обратный вызов в другом потоке, поэтому обязательно выполните ниток безопасный одноэлементный образец)

0

Что именно вы хотите достичь с истекающим синглом? Я думаю, что у вас проблемы с дизайном, если вы действительно этого хотите. И, как сказал Мартин, у вас возникнут проблемы, если какой-то код «захватит» вас один экземпляр.

Итак, что именно вы используете для этого? Или вопрос только из любопытства?

+0

В настоящее время класс SingleHangler класса имеет список , который содержит список категорий, загружаемых из XML-файла при первом запросе экземпляра. Меня попросили изменить это, чтобы получить категории из базы данных, и чтобы список сразу обновлялся на каждом веб-сервере, на котором запущено приложение. Ясно, что я могу заставить уничтожить singleton на том же сервере, который обновляет базу данных, но я не могу уничтожить экземпляр на других серверах. Эта идея истечения срока действия Singleton является одной из возможностей, которую я рассматриваю. – Jason

+0

@Jabberish: Если вы используете ASP.NET, то почему бы не использовать встроенный 'Cache' для этого? – LukeH

+0

Люк: это еще один вариант, который у меня есть и спасибо за предложение. – Jason

1

Чтобы избежать проблем с классами, имеющими ссылки на старый, например, вы могли бы рассмотреть возможность написания кэширования обертки для вашего класса. Кулак извлечь интерфейс ICategoryHandler, позволяет предположить, что это выглядит следующим образом:

interface ICategoryHandler 
{ 
    int A(); 
} 

, а затем вы реализуете обертку (запирание опущено):

class CategoryHandlerWrapper : ICategoryHandler 
{ 
    ICategoryHandler instance; 
    private DateTime expiry = DateTime.MinValue; 

    public int A() 
    { 
    return Instance().A(); 
    } 

    public bool HasExpired 
    { 
     get return DateTime.Now > expiry; 
    } 

    private CategoryHandler Instance() 
    { 
     if(HasExpired) 
     { 
      //Dispose and reconstruct 
     } 
     else 
     { 
      //Use existing instance 
     } 
    } 
} 

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

1

Рассматривали ли вы использование IoC/DI Container framework и управляете ли вы временем жизни «синглтон»?

Microsoft Unity - это тот, с которым я больше всего знаком, и они не предоставляют LifetimeManager из коробки, которая делает именно то, что вы хотите сделать. Однако вы можете создать своего собственного потомка; см. Writing Custom Lifetime Managers.

Или вы можете посмотреть другие рамки и посмотреть, есть ли у вас то, что вы хотите в поле.

РЕДАКТИРОВАТЬ: Обратите внимание, что это все равно не избавит вас от «захваченной» проблемы, о которой говорил Мартин.

Смежные вопросы