Я не уверен, каким должен быть наилучший подход к объектно-ориентированному проектированию в отношении конкретного шаблона состояния, который я реализую. Пожалуйста, обратите внимание на следующее:
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
. Мне кажется, что это приведет к сильной связи между Штатами и их братьями и сестрами, а также Controller
и State
.
Требования следующие:
- ДОЛЖНА быть возможность добавлять новые состояния, например, добавление
SniffingState
. Также ДОЛЖНА быть возможна замена существующих состояний новыми. Например, я должен иметь возможность заменить
OffLeachState
другимOffLeashState
, выполняющим другое действие. Например (по какой-то причине код не форматируется):public class OffLeachState2 extends DogState {
public void seeCat(Cat cat) {
if (dog.knows(cat)) {
// собака меняется на "PlayWithCatState"
// кошка получает " PlayWithDog" request
} else {
// собака меняется на "ChaseAnimalState"
}
}
}Наконец, все изменения в классе
World
ДОЛЖНЫ быть зарегистрированы. Это означает, что класс World имеет регистратор, который отслеживает все, что происходит. Это также связано с тем, что класс World является моделью и должен запускатьnotifyObservers()
, чтобы представление знало, что нужно делать.
Мой вопрос: где должны храниться состояния, запросы и т.д.? Например:
Должны ли быть "геттеры" состояния в
Dog
? например,dog.getBarkingState()
,dog.getOnLeashState()
и т.д.? Это кажется логичным, но это не делает классDog
устойчивым к изменениям. Т.е. каждый раз, когда я добавляю новый классDogState
, я также должен убедиться, чтоDog
имеет для него геттер. Кроме того,World
не знает об этих изменениях, поэтому не регистрирует их и не уведомляет наблюдателей.Должен ли быть класс под названием
DogStates
, и я могу запуститьDogStates.getBarkingState()
? Опять же, проблемы, аналогичные описанным выше.Должны ли они быть частью класса
World
? Например,world.setDogState(dog, world.getDogBarkingState()
? Это решит проблему регистрации/обновления, но возлагает слишком большую ответственность на классWorld
.Должна ли это быть какая-то их комбинация, например
world.setState(dog, dog.getBarkingState()
? Это МОЖЕТ быть хорошо, но не гарантирует безопасность типов. Например, я могу передать объектDog
сCatState
, и он не заметит разницы.
Решение №4 кажется мне лучшим, но хотелось бы и других мнений по этому вопросу.
Тот же вопрос относится и к объекту Request
. Первоначально я хотел отправить Request
s строками, которые были связаны с объектом, например world.sendRequest(dog, DogRequests.SEE_CAT)
, но тогда я не мог передать объект cat в качестве аргумента.
Большое спасибо за уделенное время!