Розмежування держав, що використовують державу

Я не впевнений у тому, що найкращий підхід до розробки ОО має стосуватися певної моделі держави, яку я реалізую. Будь ласка, враховуйте наступне:

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 {
    private State currentState_;
    ….
    public void sendRequest(RequestType request) {
        request.sendToState(currentState_);
    }
    public void setState(StateType state) {
        currentState_ = state;
    }
}

public class Dog extends Animal {
    …
}

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 {
    public void sendToState(StateType state);
}

public class DogRequest extends Request { }

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 s.

Вимоги такі:

  1. It MUST be possible to add new States, for example adding a SniffingState.
  2. It also MUST be possible to replace existing States with new ones. For example, I should be able to replace OffLeachState with a different OffLeashState 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"
    }
    }
    }

  3. 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 a notifyObservers() so that the view knows to do something.

Моє питання полягає в тому, де повинні зберігатися держави, запити тощо. Наприклад:

  1. Чи повинні бути "геттери" в Dog ? Наприклад, dog.getBarkingState() , dog.getOnLeashState() та ін? Це, мабуть, має сенс, але це не робить клас Dog стійким до змін. Тобто, кожен раз, коли я додаю новий клас DogState , я також повинен переконатися, що для цього є Dog . Крім того, World не знає про ці зміни, тому не записує їх і не повідомляє спостерігачів.

  2. Чи повинен бути клас з назвою DogStates , і я можу запустити DogStates.getBarkingState() ? Знову ж таки, подібні проблеми до одного з них вище.

  3. Чи повинні вони бути частиною класу World ? Наприклад, world.setDogState (dog, world.getDogBarkingState() ? Це дозволить вирішити проблему реєстрації/оновлення, але ставить занадто велику відповідальність за клас World .

  4. Чи повинна бути якась їх комбінація, наприклад world.setState (собака, dog.getBarkingState() ? Це може бути добре, але не забезпечує безпеку типу. Я міг передати об'єкт Dog з кодом CatState , і він не знав би різниці.

Рішення № 4 здається мені найкращим, але я хотів би отримати інші думки з цього питання.

Те саме питання стосується об'єкта Request . Спочатку я хотів відправити Request s за допомогою рядків, які були пов'язані з об'єктом, наприклад world.sendRequest (собака, DogRequests.SEE_CAT) , але тоді я не міг пройти об'єкт кота як аргумент.

Велике спасибі за ваш час!

2

1 Відповіді

1.) Це виглядає як питання екзамену на програму. У таких сценаріях, якщо ви не знаєте що робити, використовуйте шаблон ! Тому кожна держава повинна генеруватися StateFactory і надати Фабриці екземпляр деякої інформації про Світ, щоб він міг вирішити, який конкретний державний екземпляр створювати.

Ось каротаж:

public class World implements StateChangeListener {
  private Animal dog_;
  private Animals cats_;

  private final List listeners = new ArrayList();

  public World() {
    listeners.add(this);
  }

 //Instead of sending DogRequests to Dogs via the sendDogRequest method:
  public  void sendRequest(
      Animal request) {
    animal.sendRequest(request);
    for(StateChangeListener listener : listeners) {
      listener.stateChanged(animal, request);
    }
  }

  public void stateChanged(Animal<?, ?> animal, State<?> state) {
   //... log here ...
  }
...

І цей заводський матеріал (можливо, трохи розсіяний, Generics може не працювати правильно; o).

public enum LocationEnum {
  HOME, PARK, POND, FOREST
}

public interface StateFactory {
  State create(Animal {
  public State create(Animal {
  private StateFactory stateFactory;
  private State currentState_;

  public void sendRequest(Request 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 {
  public Dog() {
    this.stateFactory = new DogStateFactory();
  }
}

2.) Якщо ви хочете, щоб Світ знав усе, що відбувається в ньому, ви можете замінити державні установи, які не мають повідомлень, і дозволити інстанції світу слухати всі зміни у державі.

0
додано
"Якщо ви не знаєте, що робити, використовуйте шаблон". - Це як би сказати, якщо ви не знаєте, що робити з проблемою у вашому домі, використовуйте клейку стрічку.
додано Автор Fuhrmanator, джерело
Державний шаблон має багато складності для інкапсуляції логіки держави для всіх переходів (операцій). Книга GoF каже, що вона повинна застосовуватися, коли "операції мають великі, багаточастинні умовні вирази, які залежать від стану об'єкта". Див angry-architect.blogspot.ca/2006/08/& hellip; для спрощення альтернатив, якщо ваші операції є простими.
додано Автор Fuhrmanator, джерело
@Fuhrmanator "якщо ви не знаєте, що робити з проблемою у вашому домі, використовуйте клейку стрічку" - Ну, це хороша порада, чи не так?
додано Автор MC Emperor, джерело
В порядку. Давайте подивимося, що мій розлючений мій вечеряє мозок ... Я буду редагувати мою відповідь вище.
додано Автор chabicht, джерело
Я не впевнений, що так багато похвали є доречним. : o)
додано Автор chabicht, джерело
Велике спасибі за швидку відповідь! Не могли б ви уявити якийсь приклад коду? Для 1, моє розуміння буде, що це буде включати щось на зразок 'dogStateFactory.createBarkingState ()'? Для 2, ви поставите 'notifyWorld ()' після встановлення нового стану?
додано Автор Jean of mArc, джерело
Дякую! О, і, можливо, я повинен почати писати екзамени з програмування. :) Я підібрав весь сценарій, щоб виділити проблему, яку я маю у більшому контексті.
додано Автор Jean of mArc, джерело
Ого, дякую ДУЖЕ багато для всіх того, що ви працюєте в своїх прикладах! Ви повинні написати підручник або щось ха-ха. Вони повинні напевно дати мені кілька ідей щодо того, що я повинен робити. Знову дякую!
додано Автор Jean of mArc, джерело
Я буду впевнений, що 1-ваша відповідь, як тільки у мене є достатньо репутаційних точок. :)
додано Автор Jean of mArc, джерело
ІТ КПІ - Java
ІТ КПІ - Java
436 учасників