2つのプロパティがあるclass Car
があります:int price
とboolean inStock
。また、List
of abstract class State
(空のクラス)も保持します。車に適用できる2つの状態があり、それぞれが独自のクラスで表されます:class Upgrade extends State
およびclass Shipping extends State
。
Car
は、2つの状態をそれぞれいくつでも保持できます。州には次の規則があります。
Upgrade
:自動車の後に適用される各州の価格に1
を追加します。Shipping
:リストに少なくとも1つのShipping
状態がある場合、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);
}
}
明らかに、これは機能しません。 Shipping
が削除されると、somethingは、inStock
をfalseに設定する別の状態があるかどうかを確認する必要があるため、 Shipping
の削除はinStock = true
だけではありません。 Upgrade
は、呼び出しごとにprice
を増やします。次に、デフォルト値の定数を追加し、それらに基づいて再計算を試みました。
私は決してパターンを課そうとしているのではなく、上記の要件の解決策を見つけようとしているだけです。実際にはCar
には多くのプロパティが含まれ、この方法で適用できる多くの状態があることに注意してください。私はこれを行ういくつかの方法を考えました:
Car
を受け取るため、現在登録されている他のすべてのオブザーバーを確認し、それに基づいて変更を加えることができます。このようにオブザーバーを巻き込むことが賢明かどうかはわかりません。Car
に追加または削除されると、再計算されます。ただし、この再計算は、allオブザーバーで、追加または削除されたオブザーバーに関係なく実行する必要があります。説明されている動作を実装するための適切な設計パターンは何ですか?どのように機能しますか?
私はオプション3を使用してしまいました-外部マネージャーを使用します。マネージャーは、State
sからCar
sを追加および削除し、これらの変更が発生したときにオブザーバーに通知する責任があります。
これが私がコードを変更した方法です。独自の実装を行っているため、JDKのObservable
/Observer
を削除しました。
各State
は、そのCar
への参照を保持します。
abstract class State {
Car car;
State(Card car) { this.car = car; }
public abstract void update();
}
class Upgrade extends State {
@Override
public void update() {
int bonus = car.states.size() - car.states.indexOf(this) - 1;
car.price += bonus;
System.out.println(car.inStock + " " + car.price);
}
}
class Shipping extends State {
@Override
public void update() {
car.inStock = false;
System.out.println(car.inStock + " " + car.price);
}
}
Car
はその状態のみを保持し(混乱を避けるため:プロパティ)、State
sの追加と削除は処理しません。
class Car extends Observable {
List<State> states = new ArrayList<>();
int price = 100;
boolean inStock = true;
}
こちらがマネージャーです。 Car
s(オブザーバー)を管理するState
s(監視可能)ジョブを追い越しました。
class StatesManager {
public void addState(Card car, State state) {
car.states.add(state);
for (State state : car. states)
state.update;
}
public void removeState(Card car, State state) {
car.states.remove(state);
for (State state : car. states)
state.update;
}
}
覚えておくべきいくつかのこと:
update
メソッドへの不要な呼び出しを排除できます。update
メソッドをupdateOnAdd
とupdateOnRemove
に分割できます。次に、addState
およびremoveState
メソッドがそれに応じて更新されます。前のポイントに加えて、このアプローチは、堅牢で拡張可能で柔軟なメカニズムになる可能性があります。State
sを追加および削除する指示を与えるもの、およびそれがいつ発生するかは、質問には重要ではないため、指定しませんでした。ただし、この回答の場合、次の点を考慮する必要があります。 State
は、マネージャーのメソッドを呼び出す前にCar
(空のコンストラクターが公開されていない)で作成する必要があるため、addState
およびremoveState
メソッドは必要ありません。 Car
を取得し、state.car
から読み取ることができます。異なる方法でシステムを因数分解すると、オブザーバーはうまく機能します。状態自体をオブザーバーにする代わりに、2つの新しいクラスを「状態変更オブザーバー」にすることができます。1つのオブザーバーが「price」を更新し、別のオブザーバーが「inStock」を更新します。このように、inStockに依存する価格のルールがない場合、またはその逆の場合、つまり状態の変化を見ることだけですべてを計算できる場合、それらは独立しています。この手法は「イベントソーシング」と呼ばれます(たとえば、- https://ookami86.github.io/event-sourcing-in-practice/ を参照してください)。注目すべきアプリケーションがいくつかあるのは、プログラミングのパターンです。
より一般的な質問に答えると、オブザーバー間に依存関係がある場合があります。たとえば、ある観察者が別の観察者の前に反応するようにしたい場合があります。このような場合、通常、Observableクラスのカスタム実装を作成して、順序や依存関係を処理することができます。