Apakah pola pengamat cocok ketika pengamat tidak independen satu sama lain?

9

Saya memiliki class Caryang memiliki 2 properti: int pricedan boolean inStock. Hal ini juga memegang Listdari abstract class State(kelas kosong). Ada 2 negara yang dapat diterapkan pada mobil dan masing-masing diwakili oleh kelasnya sendiri: class Upgrade extends Statedan class Shipping extends State.

A Cardapat menampung sejumlah dari masing-masing 2 negara. Negara bagian memiliki aturan berikut:

  • Upgrade: menambah 1harga untuk setiap negara diterapkan untuk mobil setelah itu sendiri.
  • Shipping: jika setidaknya ada 1 Shippingstatus dalam daftar, maka inStockdiatur ke false.

Misalnya, dimulai dengan price = 1dan 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 Shippingdihapus, sesuatu harus memeriksa apakah ada pengaturan negara lain inStockke false, jadi penghapusan Shippingtidak bisa adil inStock = true. Upgrademeningkat pricepada 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 Carberisi banyak properti dan ada banyak negara yang dapat diterapkan dengan cara ini. Saya memikirkan beberapa cara untuk melakukan ini:

  1. 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.
  2. 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.
  3. 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?

pengguna1803551
sumber
1
Maksud dari abstrak State ke dalam kelasnya sendiri adalah untuk memisahkan Logic yang tidak saling berinteraksi, menyederhanakan kode. Namun, logika bisnis Anda menentukan bahwa Logika mereka terkait, dan karenanya, Anda harus menyelipkan kembali tautan tersebut, yang mengakibatkan kekacauan yang mengerikan ini. Bukan pola pengamat yang menjadi masalah di sini, melainkan pola Peran yang Anda terapkan dengan Negara.
ArTs
Bagaimana Anda memecahkan masalah jika Anda melakukannya dengan tangan?
James Youngman
@YamesYoungman Saya akhirnya menggunakan opsi ke-3 saya - manajer eksternal. Aturan penulisan Anda di atas kertas untuk kasus ini sederhana, tetapi opsi yang diberikan bahasa untuk Anda terapkan terbatas dalam kasus ini . Karenanya kebutuhan akan pola desain. Berpikir tentang "bagaimana Anda akan melakukannya dengan tangan" bekerja lebih untuk algoritma daripada menerapkan seperangkat aturan yang jelas.
user1803551
@ user1803551 Anda memilih dengan baik.
Tulains Córdova
Miliki satu pengendali acara untuk semua acara. Pawang ini hanyalah titik masuk untuk menghitung ulang keadaan lengkap objek. Ini masalah tipikal. Anda melihatnya nyata ketika mengerjakan formulir "atas ke bawah, kiri ke kanan" - semuanya A-OK, tetapi kemudian mengubah sesuatu di tengah tidak dihitung ulang dengan benar. Jika Anda akhirnya bertanya "bagaimana saya bisa menjamin pesanan penanganan acara?", Sekarang Anda tahu apa yang harus Anda lakukan.
radarbob

Jawaban:

1

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.

battlmonstr
sumber
0

Saya akhirnya pergi dengan opsi 3 - menggunakan manajer eksternal. Manajer bertanggung jawab untuk menambah dan menghapus Statedari Cardan untuk memberitahu pengamat ketika perubahan ini terjadi.

Inilah cara saya memodifikasi kodenya. Saya menghapus Observable/ Observerdari JDK karena saya sedang melakukan implementasi saya sendiri.

Masing-masing Statemenyimpan referensi ke Caryang diterapkan.

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);
    }
}

Carhanya memegang statusnya (untuk menghindari kebingungan: properti) dan tidak menangani penambahan dan penghapusan States:

class Car extends Observable {

    List<State> states = new ArrayList<>();
    int price = 100;
    boolean inStock = true;
}

Inilah manajernya. Ini telah mengambil alih pekerjaan Car(yang dapat diamati) mengelola State(pengamat).

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;
    }
}

Beberapa hal yang perlu diingat:

  • Semua pengamat diberitahu tentang setiap perubahan. Skema distribusi acara yang lebih pintar dapat menghilangkan panggilan yang tidak dibutuhkan ke updatemetode pengamat .
  • Para pengamat mungkin ingin mengekspos lebih banyak metode "pembaruan" seperti untuk berbagai kesempatan. Sama seperti contoh, mereka dapat membagi updatemetode saat ini ke updateOnAdddan updateOnRemovejika mereka hanya tertarik pada salah satu perubahan ini. Maka metode addStatedan removeStateakan diperbarui sesuai. Seiring dengan poin sebelumnya, pendekatan ini dapat berakhir sebagai mekanisme yang kuat, dapat dikembangkan, dan fleksibel.
  • Saya tidak menentukan apa yang memberi instruksi untuk menambah dan menghapus Statedan ketika itu terjadi karena tidak penting untuk pertanyaan. Namun, dalam hal jawaban ini, ada beberapa hal yang perlu dipertimbangkan. Karena Statesekarang harus dibuat dengan Car(tidak ada konstruktor kosong yang terbuka) sebelum memanggil metode manajer, addStatedan removeStatemetode tidak perlu mengambil Cardan hanya dapat membacanya state.car.
  • Pengamat diberitahu dalam urutan pendaftaran pada diamati secara default. Urutan yang berbeda dapat ditentukan.
pengguna1803551
sumber