У меня class Car
есть 2 свойства: int price
и boolean inStock
. Он также держит List
из abstract class State
(пустого класса). Есть 2 состояния, которые могут быть применены к автомобилю, и каждый представлен своим собственным классом: class Upgrade extends State
и class Shipping extends State
.
A Car
может содержать любое количество каждого из 2 состояний. В штатах действуют следующие правила:
Upgrade
: добавляет1
к цене для каждого государства, примененного к автомобилю после себя.Shipping
: еслиShipping
в списке хотя бы 1 состояние,inStock
устанавливается значениеfalse
.
Например, начиная с price = 1
и inStock = true
:
add Shipping s1 --> price: 1, inStock: false
add Upgrade g1 --> price: 1, inStock: false
add Shipping s2 --> price: 2, inStock: false
add Shipping s3 --> price: 3, inStock: false
remove Shipping s2 --> price: 2, inStock: false
remove Upgrade g1 --> price: 1, inStock: false
remove Shipping s1 --> price: 1, inStock: false
remove Shipping s3 --> price: 1, inStock: true
Я думал о шаблоне наблюдателя, где каждая операция добавления и удаления уведомляет наблюдателей. Я имел в виду нечто подобное, но оно не подчиняется правилам, которые я изложил:
abstract class State implements Observer {
public abstract void update();
}
class Car extends Observable {
List<State> states = new ArrayList<>();
int price = 100;
boolean inStock = true;
void addState(State state) {
if (states.add(state)) {
addObserver(state);
setChanged();
notifyObservers();
}
}
void removeState(State state) {
if (states.remove(state)) {
deleteObserver(state);
setChanged();
notifyObservers();
}
}
}
class Upgrade extends State {
@Override
public void update(Observable o, Object arg) {
Car c = (Car) o;
int bonus = c.states.size() - c.states.indexOf(this) - 1;
c.price += bonus;
System.out.println(c.inStock + " " + c.price);
}
}
class Shipping extends State {
@Override
public void update(Observable o, Object arg) {
Car c = (Car) o;
c.inStock = false;
System.out.println(c.inStock + " " + c.price);
}
}
Очевидно, это не работает. Когда a Shipping
удаляется, что-то должно проверить, есть ли другое состояние, установленное inStock
в false, поэтому удаление Shipping
не может просто inStock = true
. Upgrade
увеличивается price
при каждом вызове. Затем я добавил константы для значений по умолчанию и попытался пересчитать их.
Я ни в коем случае не пытаюсь навязать какой-либо шаблон, я просто пытаюсь найти решение для вышеуказанных требований. Обратите внимание, что на практике Car
содержится много свойств, и существует много состояний, которые можно применять таким образом. Я думал о нескольких способах сделать это:
- Поскольку каждый наблюдатель получает
Car
, он может просматривать всех других наблюдателей, зарегистрированных в настоящее время, и вносить в них изменения. Я не знаю, разумно ли так запутывать наблюдателей. - Когда наблюдатель будет добавлен или удален
Car
, произойдет перерасчет. Тем не менее, этот пересчет должен быть сделан для всех наблюдателей, независимо от того, который был только что добавлен / удален. - Иметь внешний класс "manager", который будет вызывать методы add и remove и выполнять пересчет.
Что такое хороший шаблон проектирования для реализации описанного поведения и как оно будет работать?
источник
Ответы:
Наблюдатели будут отлично работать, если вы по-разному учитываете систему. Вместо того, чтобы делать состояния самими наблюдателями, вы можете сделать 2 новых класса «наблюдателями изменений состояния»: один наблюдатель обновит «цену», другой обновит «inStock». Таким образом, они будут независимы, если у вас нет правил для цены в зависимости от inStock или наоборот, т.е. если все можно рассчитать, просто посмотрев на изменения состояния. Этот метод называется «источником событий» (например, см. Https://ookami86.github.io/event-sourcing-in-practice/ ). Это паттерн в программировании, который имеет некоторые известные приложения.
Отвечая на более общий вопрос, иногда у вас действительно есть зависимости между наблюдателями. Например, вы можете захотеть, чтобы один наблюдатель реагировал раньше другого. В таком случае обычно можно создать собственную реализацию класса Observable для работы с порядком или зависимостями.
источник
В итоге я выбрал вариант 3 - использование внешнего менеджера. Менеджер отвечает за добавление и удаление
State
s изCar
s, а также за уведомление наблюдателей, когда происходят эти изменения.Вот как я изменил код. Я удалил
Observable
/Observer
из JDK, потому что я делаю свою собственную реализацию.Каждый
State
хранит ссылку наCar
свою заявку.Car
только сохраняет свое состояние (чтобы избежать путаницы: свойства) и не обрабатывает добавление и удалениеState
s:Вот менеджер. Он обогнал
Car
s (наблюдаемую) работу по управлению своимиState
(наблюдателями).Несколько вещей, которые нужно иметь в виду:
update
метода наблюдателей .update
метод наupdateOnAdd
и,updateOnRemove
если они заинтересованы только в одном из этих изменений. ТогдаaddState
иremoveState
методы будут обновлены соответствующим образом . Наряду с предыдущим пунктом этот подход может в конечном итоге стать надежным, расширяемым и гибким механизмом.State
s и когда это происходит, поскольку это не важно для вопроса. Тем не менее, в случае этого ответа, есть следующий момент для рассмотрения. Поскольку вState
настоящее время должен быть создан с егоCar
(не пустой конструктор подвергается) до вызова метода менеджера, тоaddState
иremoveState
методы не должны приниматьCar
и может просто прочитать его изstate.car
.источник