使用状态模式解耦状态
我不确定对于我正在实现的特定状态模式,最佳的面向对象设计方法应该是什么。请考虑以下事项:
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”一词的用法,即。使用另一个 State 实例化一个 new SomeState()
,或者在 Controller
或另一个 State
中实例化 new SomeRequest()
。在我看来,这会在 State 及其兄弟姐妹之间以及 Controller
和 State
之间产生高度耦合。
要求如下:
- 必须能够添加新的状态,例如添加
SniffingState
。 还必须能够用新的状态取代现有的状态。例如,我应该能够用执行不同操作的不同
OffLeashState
替换OffLeachState
。例如(由于某种原因代码不会格式化):公共类 OffLeachState2 扩展了 DogState {
公共无效seeCat(猫猫){
if (dog.knows(cat)) {
// 狗更改为“PlayWithCatState”
// cat 收到“PlayWithDog”请求
} 否则{
// 狗更改为“ChaseAnimalState”
}
}
}- 最后,
World
类中的所有更改都必须被记录。这意味着世界级有一个记录器可以跟踪正在发生的一切。这也是因为 World 类是一个模型,并且必须触发notifyObservers()
以便视图知道要执行某些操作。
我的问题是,状态、请求等应该存储在哪里?例如:
Dog
中应该有状态“getters”吗?例如,dog.getBarkingState()、dog.getOnLeashState()等?这似乎有道理,但它并不会使Dog
类抵制更改。即,每次添加新的DogState
类时,我还必须确保Dog
有一个 getter。此外,World
不知道这些更改,因此它不会记录它们,也不会通知观察者。是否应该有一个名为
DogStates
的类并且我可以运行DogStates.getBarkingState()
?再次出现与上面类似的问题。它们应该是
World
类的一部分吗?例如,world.setDogState(dog, world.getDogBarkingState()
?这可以解决日志记录/更新问题,但会给World
类带来太多责任。 p>应该是它们的某种组合吗,例如
world.setState(dog,dog.getBarkingState()
)?这可能会很好。 ,但不能保证类型安全。例如,我可以传入Dog
对象和CatState
,但它不会知道其中的区别。
解决方案 #4 对我来说似乎是最好的,但我想了解有关此问题的一些其他意见。
同样的问题也适用于 Request
对象。我最初想通过与对象关联的字符串发送请求,例如 world.sendRequest(dog, DogRequests.SEE_CAT) ,但后来我无法通过cat 对象作为参数。
非常感谢您抽出时间!
I am unsure as to what the best OO design approach should be regarding a particular State pattern I am implementing. Please consider the following:
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));
}
…
}
My area of hesitation is with the usages of the word new
here, ie. instantiating a new SomeState()
with another State, or new SomeRequest()
within the Controller
or another State
. It seems to me that this would produce high coupling between the States and their siblings, as well as the Controller
and State
s.
The requirements are as follows:
- It MUST be possible to add new States, for example adding a
SniffingState
. It also MUST be possible to replace existing States with new ones. For example, I should be able to replace
OffLeachState
with a differentOffLeashState
that performs a different action. For example (for some reason the code won't format):public class OffLeachState2 extends DogState {
public void seeCat(Cat cat) {
if (dog.knows(cat)) {
// dog changes to "PlayWithCatState"
// cat gets a "PlayWithDog" request
} else {
// dog changes to "ChaseAnimalState"
}
}
}Finally, all changes within the
World
class MUST be logged. That means that the World class has a logger which is keeping track of everything that is going on. This is also because the World class is a model, and has to fire off anotifyObservers()
so that the view knows to do something.
My question is, where should the states, requests etc be stored? For example:
Should there be state "getters" in
Dog
? for example,dog.getBarkingState()
,dog.getOnLeashState()
, etc? This seems to make sense, but it doesn't make theDog
class resistant to change. Ie, every time I add a newDogState
class, I also have to make sure thatDog
has a getter for it. Also, theWorld
doesn't know about these changes, so it doesn't log them nor notify observers.Should there be a class called
DogStates
and I can runDogStates.getBarkingState()
? Again, similar problems to the one above.Should they be a part of the
World
class? For example,world.setDogState(dog, world.getDogBarkingState()
? This would solve the logging/updating problem, but puts too much responsibility on theWorld
class.Should it be some combination thereof, for example
world.setState(dog, dog.getBarkingState()
? This COULD be good, but doesn't assure type safety. For example, I could pass in aDog
object with aCatState
, and it wouldn't know the difference.
Solution #4 seems the best to me, but I would like some other opinions about this issue.
The same question applies to the Request
object. I originally wanted to send Request
s by Strings which were associated with an object, for example world.sendRequest(dog, DogRequests.SEE_CAT)
, but then I couldn't pass the cat object as an argument.
Thank you very much for your time!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
1.) 这看起来像是一道编程考试题。在这种情况下,如果不确定该怎么做,使用模式!因此,每个 State 都应该由 StateFactory 生成,并为 Factory 实例提供一些有关 World 的信息,以便它可以决定创建哪个特定 State 实例。
这是日志记录的内容:
还有工厂的内容(可能有点心不在焉,泛型可能无法正常工作;o)。
2.) 如果你想让世界知道其中发生的一切,你可以用消息代替状态设置者,让世界实例监听每个人的状态变化。
1.) This looks like a programming exam question. In such scenarios, if unsure what to do, use a Pattern! So every State should be generated by a StateFactory and give the Factory instance some information about the World so it can decide which specific State instance to create.
Here's the logging stuff:
And that Factory stuff (probably a bit scatterbrained, Generics might not work correctly ;o).
2.) If you want the World to know everything happening in it, you could substitute the state setters whith messages and let the World instance listen to everybody's state changes.