I have a class Car
which has 2 properties: int price
and boolean inStock
. It also holds a List
of abstract class State
(empty class). There are 2 states which can be applied on the car and each is represented by its own class: class Upgrade extends State
and class Shipping extends State
.
A Car
can hold any number of each of the 2 states. The states have the following rules:
Upgrade
: adds1
to the price for each state applied to the car after itself.Shipping
: if there is at least 1Shipping
state in the list, theninStock
is set tofalse
.
For example, starting with price = 1
and 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
I was thinking about the observer pattern where each add and remove operations notify observers. I had something like this in mind, but it doesn't obey the rules I posed:
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);
}
}
Obviously, this doesn't work. When a Shipping
is removed, something has to check if there is another state setting inStock
to false, so a removal of Shipping
can't just inStock = true
. Upgrade
increases price
at each call. I then added constants for the default values and attempted a recalculation based on those.
I am by no means trying to impose any pattern, I'm just trying to find a solution for the above requirements. Note that in practice Car
contains many properties and there are many states that can be applied in this manner. I thought about a few ways to do this:
- Since each observer receives
Car
, it can look at all the other observers currently registered and make a change based on that. I don't know if it's smart to entangle observers like this. - When an observer is added or removed in
Car
, there will be a recalculation. However, this recalculation will have to be done on all observers regardless of the one which was just added/removed. - Have an external "manager" class which will call the add and remove methods and do the recalculation.
What is a good design pattern to implement the described behavior and how would it work?