アップデート:
私は実際に今朝、あなたの特定のケースで機能し、保守がはるかに簡単になる方法を考えました。ここでは元の2つのポイントを残しますが、代わりに最後のオプションをお勧めしますので、「より良い方法」のセクションにスキップしてください。
ThrowIfReadOnly
缶に書かれていることを行うメソッドを作成します。これにより、繰り返しがわずかに少なくなり、ネストが回避されます。
インターフェイスを使用します。必要なIPage
機能を実装するを持ち、すべてのパブリックメソッドにを返しIPage
、次に、との2つの実装を持ちEditablePage
ますReadOnlyPage
。ReadOnlyPage
誰かがそれを変更しようとすると、ただ例外をスローします。また、インターフェイスに1IsReadOnly
つまたは複数のState
プロパティを配置して、IPage
コンシューマーが例外をキャッチせずに実際にステータスを確認できるようにします。
オプション(2)は、多かれ少なかれどのようIList
にReadOnlyCollection<T>
連携するかです。これにより、すべてのメソッドの最初にチェックを行う手間が省けます(したがって、検証を忘れるリスクがなくなります)が、2つのクラスを維持する必要があります。
-より良い方法-
適切な技術仕様は、この問題を明確にするのに大いに役立ちます。ここに実際にあるのは次のとおりです。
- 一連の任意の「書き込み」アクション。
- 状態に応じて、各アクションの結果は同じです。
- アクションが実行される(未公開/リワーク)か、失敗/操作なし(読み取り専用)のいずれかです。
本当に抽象化する必要があるのは、アクション自体ではなく、アクションの実行です。したがって、ここで少し機能的に優れていると役立ちます。
public enum PublishingState
{
Unpublished,
Published,
Reworking
}
public delegate void Action();
public class PublishingStateMachine
{
public PublishingState State { get; set; }
public PublishingStateMachine(PublishingState initialState)
{
State = initialState;
}
public void Write(Action action)
{
switch (State)
{
case PublishingState.Unpublished:
case PublishingState.Reworking:
action();
break;
default:
throw new InvalidOperationException("The operation is invalid " +
"because the object is in a read-only state.");
}
}
}
これで、クラス自体を作成するのはほとんど簡単になります。
public class Page
{
private PublishingStateMachine sm = new
PublishingStateMachine(PublishingState.Unpublished);
private string title;
private string category;
// Snip other methods/properties
// ...
public string Title
{
get { return title; }
set { sm.Write(() => title = value; }
}
public string Category
{
get { return category; }
set { sm.Write(() => category = value; }
}
public PublishingState State
{
get { return sm.State; }
set { sm.State = value; }
}
}
これは多かれ少なかれStateパターンを実装するだけでなく、異なる状態に対して別々のクラスや別々のコードパスを維持する必要もありません。たとえば、を操作なしに変えたい場合は、メソッドからステートメントをInvalidOperationException
削除するだけです。または、そのような状態を追加する場合は、1行追加するだけです。throw
Write
Reviewing
case
これは、状態遷移や、状態に応じて異なることを行う非常に複雑なアクション(単に「成功」または「失敗」以外)を処理しませんが、それが必要なようには思えません。したがって、これにより、使用する追加のコードをほとんど必要としないドロップイン状態の実装が得られます。
もちろん、依存性注入/ AOPのオプションはまだありますが、そのアプローチには明らかに多くのオーバーヘッドがあり、私はおそらくそれをそれほど単純なものには使用しないでしょう。