我在C#中为我的控制台应用程序实现了一个Timeout。 我有一个名为MySession的类,它必须受会话超时的约束。这意味着在类的构造函数中,我为创建的对象配置了超时。如果在指定的超时内未调用类中的任何方法,则在后续访问任何方法时,必须抛出超时异常。
这是该类的虚拟实现。
public class MySession {
private TimeSpan timeout;
private DateTime lastAccessedTime;
public MySession(TimeSpan timeout) {
this.timeout = timeout;
lastAccessedTime = DateTime.Now;
}
public void StoreName(string name) {
TimeSpan diff = DateTime.Now - lastAccessedTime;
if(diff.Ticks - timeout.Ticks > 0) {
throw new TimeoutException("session timed out");
}
//store logic
lastAccessedTime = DateTime.Now;
}
public void StoreAddress(string address) {
TimeSpan diff = DateTime.Now - lastAccessedTime;
if(diff.Ticks - timeout.Ticks > 0) {
throw new TimeoutException("session timed out");
}
//store logic
lastAccessedTime = DateTime.Now;
}
public void Commit() {
TimeSpan diff = DateTime.Now - lastAccessedTime;
if(diff.Ticks - timeout.Ticks > 0) {
throw new TimeoutException("session timed out");
}
//commit logic
lastAccessedTime = DateTime.Now;
}}
我有两个问题。
编辑:(由于原始问题中未提及这些要点)
答案 0 :(得分:2)
在其他任何事情之前,您应该考虑重新思考您的会话对象应该负责的内容。通常,当我看到Commit
方法时,我也会查找Rollback
方法,以确保在操作失败时您的更新在某种程度上是一致的(尽管我仍然不确定该类是什么应该这样做。
此外,如果Commit
提交由StoreSomething
方法添加的瞬态数据,那么我不明白为什么应该打开“会话”(再次,无论是什么),直到您决定实际提交。
为问题添加更好的描述和一些背景可能使我们能够长期提供更好的解决方案。
话虽如此,稍微重构的版本可能是:
首先定义一个界面(Liskov Substitution Principle):
public interface IMySession
{
void StoreName(string name);
void StoreAddress(string address);
void Commit();
}
使用基本功能(Single Responsibility Principle)实施最简单的“普通旧”会话:
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
,也对实际执行情况一无所知;所有关心的都是计时。
如果您决定添加其他功能,请考虑保留这些类,并根据需要proxying或decorating。