使用状态模式解耦状态

时间:2011-10-28 18:54:17

标签: java design-patterns structure state

我不确定最佳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()Controller内的State实例化。在我看来,这将在各州及其兄弟姐妹以及ControllerState之间产生高度耦合。

要求如下:

  1. 必须可以添加新状态,例如添加SniffingState
  2. 还必须用新的状态替换现有的状态。例如,我应该能够将OffLeachState替换为执行不同操作的其他OffLeashState。例如(由于某种原因,代码不会格式化):

    公共类OffLeachState2扩展DogState {
    public void seeCat(Cat cat){
            if(dog.knows(cat)){
                //狗改为“PlayWithCatState”
                // cat获取“PlayWithDog”请求
            其他{
                //狗改为“ChaseAnimalState”
            }
        }
    }

  3. 最后,必须记录World类中的所有更改。这意味着World类有一个记录器,可以跟踪正在发生的一切。这也是因为World类是一个模型,并且必须触发notifyObservers()以便视图知道要做某事。

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

    1. Dog中是否应该有“getters”状态?例如,dog.getBarkingState()dog.getOnLeashState()等?这似乎是有道理的,但它并没有使Dog类能够抵抗变化。即,每次添加新的DogState课程时,我还必须确保Dog有一个getter。此外,World不知道这些更改,因此它不会记录它们,也不会通知观察者。

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

    3. 他们应该成为World班级的一员吗?例如,world.setDogState(dog, world.getDogBarkingState()?这将解决日志记录/更新问题,但对World类负有太多责任。

    4. 它应该是它的某种组合,例如world.setState(dog, dog.getBarkingState()吗?这可能很好,但不能确保类型安全。例如,我可以使用Dog传递CatState对象,但它不会知道差异。

    5. 解决方案#4对我来说似乎是最好的,但我想就此问题提出一些其他意见。

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

      非常感谢你的时间!

1 个答案:

答案 0 :(得分:0)

1。)这看起来像编程考试问题。在这种情况下,如果不确定该怎么做,使用模式!因此,每个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实例听取每个人的状态变化。