Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Before anything else, you should consider <strong>rethinking</strong> what your session object should be responsible for. Usually, when I see a <code>Commit</code> method, I look for a <code>Rollback</code> method also, to make sure that your updates are in some way consistent if an operation fails (although I am still not sure what the class is supposed to do).</p> <p>Also, if <code>Commit</code> commits transient data added by your <code>StoreSomething</code> methods, then I don't see why a "Session" (again, whatever that is) should be opened at all until you decide to actually commit.</p> <p>Adding a better description and some background to the problem might allow us to provide a better solution in the long term.</p> <p>Having said that, a slightly more refactored version might be:</p> <ol> <li><p><strong>Start by defining an interface first (<a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle" rel="nofollow">Liskov Substitution Principle</a>):</strong></p> <pre><code>public interface IMySession { void StoreName(string name); void StoreAddress(string address); void Commit(); } </code></pre></li> <li><p><strong>Implement a simplest "plain old" session with basic functionality (<a href="http://en.wikipedia.org/wiki/Single_responsibility_principle" rel="nofollow">Single Responsibility Principle</a>):</strong></p> <pre><code>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 } </code></pre></li> <li><p><strong>Finally, create a proxy class, which checks for timeouts, and forwards method calls to the base class:</strong></p> <pre><code>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(() =&gt; _baseSession.StoreName(name)); } public void StoreAddress(string address) { IfNotTimedOut(() =&gt; _baseSession.StoreAddress(address)); } public void Commit() { IfNotTimedOut(() =&gt; _baseSession.Commit()); } #endregion private void IfNotTimedOut(Action action) { if (DateTime.Now - _lastAccessedTime &gt; _timeout) { throw new TimeoutException("session timed out"); } action(); _lastAccessedTime = DateTime.Now; } } </code></pre></li> </ol> <p><strong>Overall result:</strong></p> <ul> <li><p>Other parts of your code should accept an <code>IMySession</code> object, not caring how it's actually implemented under the hood.</p></li> <li><p>Even the <code>TimeLimitedSessionProxy</code> accepts an <code>IMySession</code> and is ignorant about the actual implementation; all it cares about is timing.</p></li> <li><p>If you decide to add other functionality, consider leaving these classes intact and <a href="http://en.wikipedia.org/wiki/Proxy_pattern" rel="nofollow">proxying</a> or <a href="http://en.wikipedia.org/wiki/Decorator_pattern" rel="nofollow">decorating</a> them as needed.</p></li> </ul>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload