2009 Advent Calendar December 8th

So far we've kind of assumed for most of the time that the ImportantObject is easy to create. If not you probably want to create an interface for the ImportantObject. And creating an interface is probably a good idea anyway. So this is a refactoring of all code we have from yesterday.

    1:      public interface ImportantInterface
   2:      {
   3:          void ImportantMethod();
   4:      }
   5:   
   6:      public class ImportantObject : ImportantInterface
   7:      {
   8:          public void ImportantMethod()
   9:          {
  10:              // Do things.
  11:          }
  12:      }
  13:   
  14:      public interface Lock
  15:      {
  16:          void Lock();
  17:          void Unlock();
  18:      }
  19:   
  20:      public class MutexLock : Lock
  21:      {
  22:          private readonly Mutex _lock = new Mutex();
  23:   
  24:          public void Lock()
  25:          {
  26:              _lock.WaitOne();
  27:          }
  28:   
  29:          public void Unlock()
  30:          {
  31:              _lock.ReleaseMutex();
  32:          }
  33:      }
  34:   
  35:      public class Transaction : IDisposable
  36:      {
  37:          private readonly Lock _lock;
  38:          public ImportantInterface ImportantObject { get; private set; }
  39:   
  40:          public Transaction(ImportantInterface importantObject, Lock aLock)
  41:          {
  42:              ImportantObject = importantObject;
  43:              _lock = aLock;
  44:              _lock.Lock();
  45:          }
  46:   
  47:          public void Dispose()
  48:          {
  49:              _lock.Unlock();
  50:          }
  51:      }
  52:   
  53:      class FakeLock : Lock
  54:      {
  55:          public bool IsLocked { get; private set; }
  56:   
  57:          public FakeLock()
  58:          {
  59:              IsLocked = false;
  60:          }
  61:   
  62:          public void Lock()
  63:          {
  64:              IsLocked = true;
  65:          }
  66:   
  67:          public void Unlock()
  68:          {
  69:              IsLocked = false;
  70:          }
  71:      }
  72:   
  73:      class DummyObject : ImportantInterface
  74:      {
  75:          public void ImportantMethod()
  76:          {
  77:              Assert.True(false, "Dummy should never be used");
  78:          }
  79:      }
  80:   
  81:      public class When_using_a_transaction
  82:      {
  83:          private FakeLock _lock;
  84:   
  85:          public When_using_a_transaction()
  86:          {
  87:              _lock = new FakeLock();
  88:          }
  89:   
  90:          [Fact]
  91:          void It_should_take_lock_when_created()
  92:          {
  93:              Assert.False(_lock.IsLocked);
  94:              using (Transaction transaction = new Transaction(new ImportantObject(), _lock))
  95:              {
  96:                  Assert.True(_lock.IsLocked);
  97:              }
  98:          }
  99:   
 100:          [Fact]
 101:          void It_should_release_lock_when_leaving_scope()
 102:          {
 103:              using (Transaction transaction = new Transaction(new ImportantObject(), _lock))
 104:              {
 105:                  Assert.True(_lock.IsLocked);
 106:              }
 107:              Assert.False(_lock.IsLocked);
 108:          }
 109:      }
 110:   
 111:      public class Given_a_transaction
 112:      {
 113:          private Transaction _transaction = new Transaction(new DummyObject(), new FakeLock());
 114:   
 115:          [Fact]
 116:          void It_should_return_an_ImportantObject()
 117:          {
 118:              Assert.NotNull(_transaction.ImportantObject);
 119:          }
 120:      }