[英]Decoupling States using the State Pattern
对于我正在实施的特定状态模式,我不确定最好的 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
。 在我看来,这会在State
和它们的兄弟姐妹之间产生高度耦合,以及Controller
和State
。
要求如下:
SniffingState
。 还必须可以用新的状态替换现有的状态。 例如,我应该能够用执行不同操作的不同OffLeashState
替换OffLeachState
。 例如(由于某种原因,代码不会格式化):
公共类 OffLeachState2 扩展了 DogState {
公共无效seeCat(猫猫){
如果(狗。知道(猫)){
// 狗变成“PlayWithCatState”
// cat 收到“PlayWithDog”请求
} 别的 {
// 狗变成“ChaseAnimalState”
}
}
}
最后,必须记录World
类中的所有更改。 这意味着 World 类有一个记录器来跟踪正在发生的一切。 这也是因为 World 类是一个模型,并且必须触发notifyObservers()
以便视图知道要执行某些操作。
我的问题是,状态、请求等应该存储在哪里? 例如:
Dog
应该有状态“吸气剂”吗? 例如, dog.getBarkingState()
、 dog.getOnLeashState()
等? 这似乎是有道理的,但它不会使Dog
类抗拒更改。 即,每次我添加一个新的DogState
类时,我还必须确保Dog
有一个 getter。 此外, World
不知道这些变化,所以它不会记录它们也不会通知观察者。
应该有一个叫做DogStates
的类,我可以运行DogStates.getBarkingState()
吗? 同样,与上述问题类似的问题。
他们应该成为World
级的一员吗? 例如, world.setDogState(dog, world.getDogBarkingState()
? 这将解决日志记录/更新问题,但将过多的责任放在World
类上。
它应该是它们的某种组合,例如world.setState(dog, dog.getBarkingState()
?这可能很好,但不能保证类型安全。例如,我可以传入一个带有CatState
的Dog
对象,然后它不会知道有什么区别。
解决方案#4 对我来说似乎是最好的,但我想对这个问题有一些其他的意见。
同样的问题也适用于Request
对象。 我最初想通过与对象关联的字符串发送Request
s,例如world.sendRequest(dog, DogRequests.SEE_CAT)
,但后来我无法将 cat 对象作为参数传递。
非常感谢您的宝贵时间!
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 实例监听每个人的状态变化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.