書くように状態をビットマスクとして表すと、制約の説明をコードに変換できます。
if ( (state & HOT) && (state & COLD) ) {
state &= ~HOT;
state &= ~COLD; // reset both HOT and COLD flags if both are set
}
if ( (state & COLD) && (state & WET) ) {
state &= ~WET; // cold items can't be wet
state |= FROZEN; // instead, they're frozen
}
if ( (state & HOT) && (state & WET) ) {
state &= ~WET; // hot and wet items dry up...
state &= ~HOT; // ...and cool down
}
// add other constraints here...
これをmakeStateConsistent()
、状態ビットをテストする前に呼び出すことができるにラップして、状態が適切であることを確認できます。
ただし、このアプローチの1つの制限は、状態変化の順序を考慮できないことです。あなたが熱くなって濡れ項目よりも濡れホットアイテムごとに異なる結果を持っている場合たとえば、あなたはこのようにそれを行うことはできません。すべてのmakeStateConsistent()
メソッドは、見ている方法についての情報なしで、ホットとウェットオブジェクトでありますそれはそのようにする必要があります。
代わりに、あなたは何ができるかISは、アイテムの状態をプライベートに(少なくとも概念的には)などのメソッドのセットを介してそれを操作coolItem()
、heatItem()
、wetItem()
、dryItem()
などなど。これにより、状態変更メソッド自体が追加の変更を処理できます。たとえば、heatItem()
メソッドは次のようになります。
if ( state & COLD ) {
state &= ~COLD; // cold items become normal temp when heated
if ( state & FROZEN ) {
state &= ~FROZEN; // ...and melt if they were frozen
state |= WET;
}
} else if ( state & WET ) {
state &= ~WET; // wet items dry up when heated, stay normal temp
} else {
state |= HOT; // dry normal temp items become hot
}
もちろん、makeStateConsistent()
状態変更メソッドにバグがある場合に備えて、バックアップとしてメソッドを使用することもできます。
また、場合によっては、不要な状態を排除することでコードを簡略化できる場合があります。たとえば、本当に別のFROZEN
状態が必要なのでしょうか、それとも、冷たいものや濡れたものを冷凍したものとして扱うだけで十分でしょうか?