2

簡単なステートマシンを定義しましょう:

public enum State {

    A, B, C, D;

    private List<State> validChange;

    static {
        A.validChange = Arrays.asList(B);
        B.validChange = Arrays.asList(C);
        C.validChange = Arrays.asList(A, D);
        D.validChange = Arrays.asList(D);
    }

    public boolean couldChange(State newState) {
        return validChange.contains(newState);
    }
}

および単純な状態オブジェクト

public class StateObject {

    private State currentState;

    public State getCurrentState() {
        return currentState;
    }

    public void setCurrentState(State currentState) {
        if (this.currentState != null && !this.currentState.couldChange(currentState)) {
            throw new IllegalStateException(String.format("Can not change from %s to %s", this.currentState, currentState));
        }
        this.currentState = currentState;
    }
}

セッターに見られるように、状態の変更が有効であることを確認します。私の質問:

  1. セッターメソッドにいくつかのロジックを追加するのは良い解決策ですか?
  2. いつロジックを追加すべきか、いつ追加すべきでないか?
  3. そうでなければ、なぜですか?
4

2 に答える 2

0
  1. 一般に、はい、セッターにロジックを含めることは問題ありません。

  2. SRPが良い考えであると思われる場合は、setter 機能に関連するロジックを追加しても問題ありません。これは主に、属性の値の変更に対するオブジェクトの整合性を維持することを意味します。

  3. 私が言ったように、これが悪い考えであるケースの 1 つは SRP 違反です。

実際、セッターには2つの責任があるため、投稿されたコードはそのような違反の例を示していると思います:

  • State新しいStateObjectインスタンスの初期化、
  • 新しい への遷移を処理しますState

正規のステート マシンの残りの部分、つまり遷移アクションを含む完全な遷移関数を実装すると、2 番目の責任がさらに明確になります。

この関心の分離が重要になる主な例は、setter インジェクションしかないコードです。この場合、初期化と遷移をどのように区別しますか? このコードでは、できません。


さらに、現在のコードはカプセル化を破っているため、 にリファクタリングvalidChangeすると、ケースがより明確になると思います。状態マシン ラベルには、状態遷移関数の「ガード仕様」が含まれています。別のステートマシンに同じラベルを付けたいとしましょう - 現在のコードでは、それはできません (コンストラクターを使用する代わりに、問題を指摘する素敵なコードのにおいさえあります。静的初期化ブロックを作成する必要があります)。StateObjectStateenum

于 2013-03-08T21:49:36.210 に答える