Прежде всего, вы должны рассмотреть переосмысление того, за что должен отвечать ваш объект сеанса. Обычно, когда я вижу метод Commit
, я ищу также метод Rollback
, чтобы убедиться, что ваши обновления каким-то образом согласованы в случае сбоя операции (хотя я все еще не уверен, что должен делать класс ).
Кроме того, если Commit
фиксирует временные данные, добавленные вашими StoreSomething
методами, то я не понимаю, почему вообще нужно открывать "Сеанс" (опять же, что бы это ни было), пока вы не решите фактически зафиксировать.
Добавление лучшего описания и некоторой предыстории проблемы может позволить нам предложить лучшее решение в долгосрочной перспективе.
Сказав это, немного более измененная версия может быть:
Сначала определите интерфейс ( Принцип подстановки Лискова ):
public interface IMySession
{
void StoreName(string name);
void StoreAddress(string address);
void Commit();
}
Реализация простейшего "простого старого" сеанса с основными функциями ( Принцип единой ответственности ):
public class BasicSession : IMySession
{
#region IMySession members
public void StoreName(string name)
{
// plain store
}
public void StoreAddress(string address)
{
// plain store
}
public void Commit()
{
// plain commit
}
#endregion
}
Наконец, создайте прокси-класс, который проверяет время ожидания и перенаправляет вызовы метода в базовый класс:
public class TimeLimitedSessionProxy : IMySession
{
private readonly IMySession _baseSession;
private readonly TimeSpan _timeout;
private DateTime _lastAccessedTime = DateTime.Now;
public TimeLimitedSessionProxy(IMySession baseSession, TimeSpan timeout)
{
_baseSession = baseSession;
_timeout = timeout;
}
#region IMySession members
public void StoreName(string name)
{
IfNotTimedOut(() => _baseSession.StoreName(name));
}
public void StoreAddress(string address)
{
IfNotTimedOut(() => _baseSession.StoreAddress(address));
}
public void Commit()
{
IfNotTimedOut(() => _baseSession.Commit());
}
#endregion
private void IfNotTimedOut(Action action)
{
if (DateTime.Now - _lastAccessedTime > _timeout)
{
throw new TimeoutException("session timed out");
}
action();
_lastAccessedTime = DateTime.Now;
}
}
Общий результат:
Другие части вашего кода должны принимать объект IMySession
, не заботясь о том, как он фактически реализован под капотом.
Даже TimeLimitedSessionProxy
принимает IMySession
и не знает о фактической реализации; все, что его волнует, это время.
Если вы решите добавить другие функции, рассмотрите возможность оставить эти классы без изменений и проксировать или , украшая их при необходимости.