Java 使用状态模式解耦状态

Java 使用状态模式解耦状态,java,design-patterns,structure,state-pattern,Java,Design Patterns,Structure,State Pattern,对于我正在实现的特定状态模式,我不确定最好的OO设计方法应该是什么。请考虑以下事项: public class World { private Animal dog_; private Animals cats_; ….. public void sendDogRequest(DogRequest request) { dog_.sendRequest(request); } … public Cat getCat(Stri

对于我正在实现的特定状态模式,我不确定最好的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));
    }
    …
}
公共类世界{
私人动物狗;
私人动物猫;
…..
公共无效sendDogRequest(DogRequest请求){
狗发送请求(请求);
}
…
公共猫getCat(字符串catName){
…
返回猫;
}
...
}
公营动物{
私有状态当前状态;
….
公共无效发送请求(请求类型请求){
请求。发送状态(当前状态);
}
公共无效设置状态(StateType状态){
当前状态=状态;
}
}
公家犬{
…
}
公共类DogState扩展了状态{
公共狗州(狗){
…
}
公共无效seeCat(Cat){}
}
仅限公共类状态扩展DogState{
公共无效seeCat(Cat){
dog.setState(新的BarkingState());
}
}
fleashstate的公共类扩展了DogState{
公共无效seeCat(Cat){
狗状态(动物状态(cat)之后的新分类);
cat.sendRequest(新的RunAwayRequest(cat));
}
}
公共接口请求{
public void sendToState(StateType状态);
}
公共类DogRequest扩展请求{}
公共类SeeCatRequest扩展了DogRequest{
私家猫;
公共搜索请求(Cat){
猫=猫;
}
公共无效sendToState(DogState状态){
state.seeCat(state);
}
}
公共类控制器(){
公共控制器(世界模型、视图){
…
}
...
已选择公共无效catName(字符串catName){
Cat=world.getCat(catName);
Dog Dog=world.getDog();
sendDogRequest(新SeeCatRequest(cat));
}
…
}
我犹豫不决的地方是这里的单词
new
的用法,即用另一个状态实例化
new SomeState()
,或
Controller
或另一个
状态中的
new SomeRequest()
。在我看来,这将在状态和它们的兄弟之间产生高度耦合,以及
控制器
状态
s

要求如下:

  • 必须能够添加新状态,例如添加
    SniffingState
  • 还必须能够用新的国家取代现有的国家。例如,我应该能够将
    OffLeachState
    替换为执行不同操作的不同
    OffLeashState
    。例如(由于某些原因,代码无法格式化):

    LeachState2的公共类扩展了DogState{
    公共空间见Cat(Cat){
    如果(狗知道(猫)){
    //狗变为“玩猫状态”
    //cat收到“PlayWithDog”请求
    }否则{
    //狗变为“追逐动物状态”
    }
    }
    }

  • 最后,必须记录
    世界
    类中的所有更改。这意味着世界级的记录器可以跟踪正在发生的一切。这也是因为世界级是一个模型,必须触发一个
    notifyobservators()
    ,以便视图知道要做什么

  • 我的问题是,状态、请求等应该存储在哪里?例如:

  • Dog
    中是否应该有状态“getter”?例如,
    dog.getBarkingState()
    dog.getOnLeashState()
    ,等等?这似乎是有道理的,但它并不能使
    Dog
    类抵制更改。也就是说,每次我添加一个新的
    DogState
    类时,我还必须确保
    Dog
    有一个getter。而且,
    World
    不知道这些更改,因此它不会记录这些更改,也不会通知观察者

  • 是否应该有一个名为
    DogStates
    的类,我可以运行
    DogStates.getBarkingState()
    ?同样,与上述问题类似

  • 他们应该成为
    世界的一部分吗?例如,
    world.setDogState(dog,world.getDogBarkingState()
    ?这将解决日志记录/更新问题,但将太多的责任放在
    world
    类上

  • 是否应该是它们的某种组合,例如
    world.setState(dog,dog.getBarkingState()
    ?这可能很好,但不能保证类型安全。例如,我可以将
    dog
    对象与
    CatState
    传递,它不会知道区别

  • 解决方案4对我来说似乎是最好的,但我想听听关于这个问题的其他意见

    同样的问题也适用于
    Request
    对象。我最初希望通过与对象关联的字符串发送
    Request
    s,例如
    world.sendRequest(dog,DogRequests.SEE_CAT)
    ,但是我无法将CAT对象作为参数传递

    非常感谢您抽出时间!

    1。)这看起来像是一个编程考试题。在这种情况下,如果不确定要做什么,请使用模式!因此每个状态都应由StateFactory生成,并向Factory实例提供一些有关世界的信息,以便它可以决定创建哪个特定的状态实例

    以下是日志记录:

    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 ...
      }
    ...
    
    公共类世界实现StateChangeListener{
    私人动物狗;
    私人动物猫;
    私有最终列表侦听器=新的ArrayList();
    公共世界(){
    添加(这个);
    }
    //不要通过sendDogRequest方法向狗发送狗请求:
    公共无效发送请求(
    动物(动物,请求){
    动物。发送请求(请求);
    for(StateChangeListener:侦听器){
    状态改变(动物,请求);
    }
    }
    公共无效状态已更改(动物,状态){
    //…在这里登录。。。
    }
    ...
    
    还有工厂里的东西
    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>();
      }
    }