2

私が実装している特定の状態パターンに関して、最適な OO 設計アプローチがどうあるべきかについては確信が持てません。次の点を考慮してください。

public class World {
    private Animal dog_;
    private Animals cats_;
    …..
    public void sendDogRequest(DogRequest request) {
        dog_.sendRequest(request);
    }
    …
    public Cat getCat(String catName) {
        …
        return cat;
    }
    ...
}

public class Animal<RequestType extends Request, StateType extends State> {
    private State<StateType> currentState_;
    ….
    public void sendRequest(RequestType request) {
        request.sendToState(currentState_);
    }
    public void setState(StateType state) {
        currentState_ = state;
    }
}

public class Dog extends Animal<DogState> {
    …
}

public class DogState extends State {
    public DogState(Dog dog) {
    …
    }
    public void seeCat(Cat cat) {   }
}

public class OnLeashState extends DogState {
    public void seeCat(Cat cat) {
        dog.setState(new BarkingState());
    }
}

public class OffLeashState extends DogState {
    public void seeCat(Cat cat) {
        dog.setState(new ChasingAfterAnimalState(cat));
        cat.sendRequest(new RunAwayRequest(cat));
    }
}

public interface Request<StateType extends State> {
    public void sendToState(StateType state);
}

public class DogRequest extends Request<DogState> { }

public class SeeCatRequest extends DogRequest {
    private Cat cat_;   
    public SeeCatRequest(Cat cat) {
        cat_ = cat;
    }
    public void sendToState(DogState state) {
        state.seeCat(state);
    }
}

public class Controller() {
    public Controller(World model, View view) {
        …
    }
    ...
    public void catSelected(String catName) {
        Cat cat = world.getCat(catName);
        Dog dog = world.getDog();
        world.sendDogRequest(new SeeCatRequest(cat));
    }
    …
}

私が躊躇しているのは、newここでの単語の使用法です。new SomeState()を別の状態でインスタンス化するか、または別のnew SomeRequest()内でインスタンス化します。これは、州とその兄弟、および とs の間の高い結合を生み出すように私には思えます。ControllerStateControllerState

要件は次のとおりです。

  1. を追加するなど、新しい状態を追加できる必要がありSniffingStateます。
  2. また、既存の状態を新しい状態に置き換えることが可能でなければなりません。たとえば、別のアクションを実行する別OffLeachStateのものに置き換えることができるはずです。OffLeashState例(何らかの理由でコードがフォーマットされません):

    public class OffLeachState2 extends DogState {
    public void seeCat(Cat cat) {
    if (dog.knows(cat)) {
    // 犬は "PlayWithCatState" に変わります
    // 猫は "PlayWithDog" リクエストを受け取り
    ます } else {
    // 犬は " に変わりますChaseAnimalState"
    }
    }
    }

  3. World最後に、クラス内のすべての変更をログに記録する必要があります。つまり、World クラスには、進行中のすべてを追跡するロガーがあるということです。これは、World クラスがモデルでありnotifyObservers()、ビューが何かを行うことを認識できるように を起動する必要があるためでもあります。

私の質問は、状態、要求などをどこに保存する必要があるかです。例えば:

  1. に状態「ゲッター」が必要Dogですか? たとえばdog.getBarkingState()、、、dog.getOnLeashState()など? Dogこれは理にかなっているように見えますが、クラスが変更に対して抵抗力を持つわけではありません。つまり、新しいクラスを追加するたびに、それにゲッターがあるDogStateことも確認する必要があります。Dogまた、 はWorldこれらの変更を認識しないため、変更をログに記録したり、オブザーバーに通知したりしません。

  2. と呼ばれるクラスが必要で、DogStates実行できますDogStates.getBarkingState()か? 繰り返しますが、上記の問題と同様の問題です。

  3. World彼らはクラスの一員であるべきですか?たとえば、world.setDogState(dog, world.getDogBarkingState()? Worldこれにより、ロギング/更新の問題は解決されますが、クラスの責任が大きくなりすぎます。

  4. たとえば、それらの組み合わせである必要がありますかworld.setState(dog, dog.getBarkingState()?これは良いかもしれませんが、型の安全性は保証されません。たとえば、Dogオブジェクトを で渡すことができますCatStateが、違いはわかりません。

解決策 #4 が私には最善のように思えますが、この問題について他の意見が欲しいです。

同じ質問がオブジェクトにも当てはまりRequestます。Requestもともと、オブジェクトに関連付けられた文字列で sを送信したかったのworld.sendRequest(dog, DogRequests.SEE_CAT)ですが、 cat オブジェクトを引数として渡すことができませんでした。

お時間をいただきありがとうございました!

4

1 に答える 1

0

1.) これはプログラミングの試験問題のようです。このようなシナリオで、何をすべきかわからない場合は、 Pattern を使用してください。したがって、すべての State は StateFactory によって生成され、Factory インスタンスに World に関する情報を与えて、作成する特定の State インスタンスを決定できるようにする必要があります。

ロギングの内容は次のとおりです。

public class World implements StateChangeListener {
  private Animal dog_;
  private Animals cats_;

  private final List<StateChangeListener> listeners = new ArrayList<StateChangeListener>();

  public World() {
    listeners.add(this);
  }

  // Instead of sending DogRequests to Dogs via the sendDogRequest method:
  public <RequestType extends Request> void sendRequest(
      Animal<RequestType, ?> animal, Request<RequestType> request) {
    animal.sendRequest(request);
    for(StateChangeListener listener : listeners) {
      listener.stateChanged(animal, request);
    }
  }

  public void stateChanged(Animal<?, ?> animal, State<?> state) {
    // ... log here ...
  }
...

そして、そのファクトリーのもの(おそらく少し散らかっていて、ジェネリックは正しく機能しないかもしれません;o)。

public enum LocationEnum {
  HOME, PARK, POND, FOREST
}

public interface StateFactory<StateType extends State> {
  State<StateType> create(Animal<StateType, ?> animal, Context context);
}

// Do stuff Dogs do.
public class DogStateFactory<DogState> {
  public State<DogState> create(Animal<DogState, ?>, Context context) {
    if(context.currentAnimalLocation==LocationEnum.POND) {
      return new IgnoreEverythingState();
    }else if(context.currentAnimalLocation==LocationEnum.HOME){
      return new PerpetualBarkState();
    }else {
      return new FollowEveryCatState();
    }
  }
}

public class Animal<RequestType extends Request, StateType extends State> {
  private StateFactory<StateType> stateFactory;
  private State<StateType> currentState_;

  public void sendRequest(Request<RequestType> request) {
    request.sendToState(currentState_);
  }

  // A specific animal knows what it wants to do, depending on it's current
  // state and it's situational context. We don't want other animals
  // to set the state for us.
  public void determineState() {
    currentState_ = stateFactory.create(this, new Context(...));
    // One might want to extend the messaging stuff in a way that
    // the World instance can log this state change.
  }
}

public class Dog extends Animal<DogRequest, DogState> {
  public Dog() {
    this.stateFactory = new DogStateFactory<DogState>();
  }
}

2.) 世界で起こっていることすべてを World に知らせたい場合は、状態セッターをメッセージに置き換えて、World インスタンスに全員の状態変化をリッスンさせることができます。

于 2011-10-28T19:04:57.257 に答える