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: adds1to the price for each state applied to the car after itself.Shipping: if there is at least 1Shippingstate in the list, theninStockis 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?