Saya memiliki class Car
yang memiliki 2 properti: int price
dan boolean inStock
. Hal ini juga memegang List
dari abstract class State
(kelas kosong). Ada 2 negara yang dapat diterapkan pada mobil dan masing-masing diwakili oleh kelasnya sendiri: class Upgrade extends State
dan class Shipping extends State
.
A Car
dapat menampung sejumlah dari masing-masing 2 negara. Negara bagian memiliki aturan berikut:
Upgrade
: menambah1
harga untuk setiap negara diterapkan untuk mobil setelah itu sendiri.Shipping
: jika setidaknya ada 1Shipping
status dalam daftar, makainStock
diatur kefalse
.
Misalnya, dimulai dengan price = 1
dan 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
Saya berpikir tentang pola pengamat di mana setiap operasi menambah dan menghapus memberi tahu pengamat. Saya memiliki sesuatu seperti ini dalam pikiran, tetapi itu tidak mematuhi aturan yang saya ajukan:
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);
}
}
Jelas, ini tidak berhasil. Ketika a Shipping
dihapus, sesuatu harus memeriksa apakah ada pengaturan negara lain inStock
ke false, jadi penghapusan Shipping
tidak bisa adil inStock = true
. Upgrade
meningkat price
pada setiap panggilan. Saya kemudian menambahkan konstanta untuk nilai-nilai default dan mencoba perhitungan ulang berdasarkan itu.
Saya sama sekali tidak mencoba untuk memaksakan pola apa pun, saya hanya mencoba mencari solusi untuk persyaratan di atas. Perhatikan bahwa dalam praktiknya Car
berisi banyak properti dan ada banyak negara yang dapat diterapkan dengan cara ini. Saya memikirkan beberapa cara untuk melakukan ini:
- Karena setiap pengamat menerima
Car
, itu dapat melihat semua pengamat lain yang saat ini terdaftar dan membuat perubahan berdasarkan itu. Saya tidak tahu apakah itu pintar untuk melibatkan pengamat seperti ini. - Ketika seorang pengamat ditambahkan atau dihapus
Car
, akan ada perhitungan ulang. Namun, perhitungan ulang ini harus dilakukan pada semua pengamat terlepas dari yang baru saja ditambahkan / dihapus. - Memiliki kelas "manajer" eksternal yang akan memanggil metode tambah dan hapus dan lakukan perhitungan ulang.
Apa pola desain yang baik untuk menerapkan perilaku yang dijelaskan dan bagaimana cara kerjanya?
sumber
Jawaban:
Pengamat akan bekerja dengan baik jika Anda memfaktorkan sistem secara berbeda. Daripada menjadikan negara sebagai pengamat, Anda bisa membuat 2 kelas baru menjadi "pengamat perubahan negara": satu pengamat akan memperbarui "harga", yang lain akan memperbarui "inStock". Dengan cara ini mereka akan independen jika Anda tidak memiliki aturan untuk harga tergantung pada inStock atau sebaliknya, yaitu jika semuanya bisa dihitung dengan hanya melihat perubahan keadaan. Teknik ini disebut "event sourcing" (misalnya lihat - https://ookami86.github.io/event-sourcing-in-practice/ ). Ini adalah pola dalam pemrograman yang memiliki beberapa aplikasi terkenal.
Menjawab pertanyaan yang lebih umum, terkadang Anda benar-benar memiliki ketergantungan antar pengamat. Misalnya, Anda mungkin ingin satu pengamat bereaksi sebelum yang lain. Dalam kasus seperti itu biasanya dimungkinkan untuk membuat implementasi kustom dari kelas yang dapat diobservasi untuk menangani pemesanan atau dependensi.
sumber
Saya akhirnya pergi dengan opsi 3 - menggunakan manajer eksternal. Manajer bertanggung jawab untuk menambah dan menghapus
State
dariCar
dan untuk memberitahu pengamat ketika perubahan ini terjadi.Inilah cara saya memodifikasi kodenya. Saya menghapus
Observable
/Observer
dari JDK karena saya sedang melakukan implementasi saya sendiri.Masing-masing
State
menyimpan referensi keCar
yang diterapkan.Car
hanya memegang statusnya (untuk menghindari kebingungan: properti) dan tidak menangani penambahan dan penghapusanState
s:Inilah manajernya. Ini telah mengambil alih pekerjaan
Car
(yang dapat diamati) mengelolaState
(pengamat).Beberapa hal yang perlu diingat:
update
metode pengamat .update
metode saat ini keupdateOnAdd
danupdateOnRemove
jika mereka hanya tertarik pada salah satu perubahan ini. Maka metodeaddState
danremoveState
akan diperbarui sesuai. Seiring dengan poin sebelumnya, pendekatan ini dapat berakhir sebagai mekanisme yang kuat, dapat dikembangkan, dan fleksibel.State
dan ketika itu terjadi karena tidak penting untuk pertanyaan. Namun, dalam hal jawaban ini, ada beberapa hal yang perlu dipertimbangkan. KarenaState
sekarang harus dibuat denganCar
(tidak ada konstruktor kosong yang terbuka) sebelum memanggil metode manajer,addState
danremoveState
metode tidak perlu mengambilCar
dan hanya dapat membacanyastate.car
.sumber