Gözlemciler birbirinden bağımsız olmadığında gözlemci modeli uygun mudur?


9

Ben var class Car2 özelliklere sahip olan: int priceve boolean inStock. Ayrıca tutan Listbir abstract class State(boş sınıfa). Arabaya uygulanabilen 2 durum vardır ve her biri kendi sınıfıyla temsil edilir: class Upgrade extends Stateve class Shipping extends State.

A Car, 2 durumun her birinin herhangi bir sayısını tutabilir. Eyaletler aşağıdaki kurallara sahiptir:

  • Upgrade: 1arabanın kendisine uygulandığı her eyalet için fiyat ekler .
  • Shipping: Shippinglistede en az 1 durum varsa inStock, olarak ayarlanır false.

Örneğin, price = 1ve ile başlayarak 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

Her ekleme ve çıkarma işleminin gözlemcileri bilgilendirdiği gözlemci modelini düşünüyordum. Aklımda böyle bir şey vardı, ama verdiğim kurallara uymuyor:

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

Açıkçası, bu işe yaramıyor. A Shippingkaldırıldığında, bir şeyininStock false olarak başka bir durum ayarı olup olmadığını kontrol etmesi gerekir, bu nedenle kaldırılması Shippingsadece olamaz inStock = true. her çağrıda Upgradeartar price. Daha sonra varsayılan değerler için sabitler ekledim ve bunlara dayalı bir yeniden hesaplama girişiminde bulundum.

Hiçbir şekilde herhangi bir model dayatmaya çalışmıyorum, sadece yukarıdaki gereksinimler için bir çözüm bulmaya çalışıyorum. Uygulamada Carbirçok özellik içerdiğini ve bu şekilde uygulanabilecek birçok durum olduğunu unutmayın. Bunu yapmanın birkaç yolunu düşündüm:

  1. Her gözlemci aldığından Car, şu anda kayıtlı olan diğer tüm gözlemcilere bakabilir ve buna göre bir değişiklik yapabilir. Bu tür gözlemcileri dolaştırmanın akıllı olup olmadığını bilmiyorum.
  2. Bir gözlemci eklendiğinde veya kaldırıldığında Car, bir yeniden hesaplama olacaktır. Ancak, bu yeniden hesaplama , yeni eklenen / kaldırılandan bağımsız olarak tüm gözlemciler üzerinde yapılmalıdır .
  3. Ekleme ve kaldırma yöntemlerini çağıran ve yeniden hesaplamayı gerçekleştirecek harici bir "yönetici" sınıfınız olsun.

Açıklanan davranışı uygulamak için iyi bir tasarım modeli nedir ve nasıl çalışır?


1
Devleti kendi sınıfına soyutlamanın amacı, birbiriyle etkileşmeyen Mantık'ı ayırmak ve kodu basitleştirmektir. Bununla birlikte, iş mantığınız Mantıklarının bağlantılı olduğunu belirler ve bu nedenle bağlantıya geri dönmeniz gerekir, bu da bu Tanrı'nın korkunç karmaşasına neden olur. Burada sorun olan gözlemci kalıp değil, Devletle uyguladığınız Rol kalıp.
ArTs

Elle yapıyorsanız sorunu nasıl çözersiniz?
James Youngman

@JamesYoungman Harici bir yönetici olan 3. seçeneğimi kullandım. Bu durum için kağıda yazma kuralları basit olmasına rağmen seçenekler dil onları sınırlıdır uygulamaya verir bu durumda . Bu nedenle bir tasarım modeline ihtiyaç vardır. "Nasıl elle yaparsınız" üzerine düşünmek algoritmalar için açık bir kurallar dizisi uygulamaktan daha çok işe yarar.
user1803551

@ user1803551 İyi seçtiniz.
Tulains Córdova

Tüm olaylar için bir olay işleyiciniz olsun. Bu işleyici, nesnenin tam durumunu yeniden hesaplamak için giriş noktasıdır. Bu baş döndürücü bir sorundur. "Yukarıdan aşağıya, soldan sağa" bir form çalışırken ortaya çıktığını görürsünüz - her şey A-OK'dir, ancak ortadaki bir şeyi değiştirmek düzgün bir şekilde yeniden hesaplanmaz. Sonunda "olay işleme siparişini nasıl garanti edebilirim?" Diye sorarsanız, şimdi ne yapmanız gerektiğini biliyorsunuz.
radarbob

Yanıtlar:


1

Sistemi farklı bir şekilde çarparsanız gözlemciler harika çalışır. Devletlerin kendilerini gözlemci yapmak yerine, 2 yeni sınıfın "durum değişikliği gözlemcisi" olmasını sağlayabilirsiniz: bir gözlemci "fiyatı" güncelleyecek, diğeri "inStock" güncelleyecektir. Bu şekilde, inStock'a bağlı olarak fiyat kurallarınız yoksa veya tam tersi, yani her şey sadece eyalet değişikliklerine bakarak hesaplanabiliyorsa bağımsız olurlar. Bu tekniğe "olay kaynağı" adı verilir (örneğin bkz. - https://ookami86.github.io/event-sourcing-in-practice/ ). Programlamada bazı önemli uygulamalara sahip bir modeldir.

Daha genel bir soruyu yanıtlarken, bazen gözlemciler arasında gerçekten bağımlılıklar vardır. Örneğin, bir gözlemcinin diğerinden önce tepki vermesini isteyebilirsiniz. Bu durumda, sipariş veya bağımlılıklarla başa çıkmak için Gözlemlenebilir sınıfın özel bir uygulamasını yapmak genellikle mümkündür.


0

Harici bir yönetici kullanarak - seçenek 3 ile gidiş sona erdi. Yönetici, States ' Carleri eklemek ve kaldırmaktan ve bu değişiklikler meydana geldiğinde gözlemcileri bilgilendirmekten sorumludur .

İşte kodu nasıl değiştirdiğim. Kendi uygulamamı yaptığım için Observable/ ObserverJDK / ' ı kaldırdım .

Her biri State, uygulamasına bir referans tutar 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);
    }
}

Caryalnızca durumunu tutar (karışıklığı önlemek için: özellikler) ve States ekleme ve kaldırma işlemlerini yapmaz :

class Car extends Observable {

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

İşte müdür. Onun (gözlemcilerini) Caryönetme işini (gözlemlenebilir) üstlendi State.

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

Unutmamanız gereken birkaç nokta:

  • Tüm gözlemciler her değişiklik hakkında bilgilendirilir. Daha akıllı bir olay dağıtım şeması, gözlemcilerin updateyöntemine yapılan gereksiz çağrıları ortadan kaldırabilir .
  • Gözlemciler, farklı durumlar için daha "güncelleme" benzeri yöntemleri ortaya koymak isteyebilirler. Örnek olarak, mevcut updateyöntemi updateOnAddve updateOnRemovebu değişikliklerden yalnızca biriyle ilgilenip ilgilenmediklerini bölebilirler . Sonra addStateveremoveState yöntemleri buna göre güncellenir. Bir önceki nokta ile birlikte bu yaklaşım sağlam, genişletilebilir ve esnek bir mekanizma olarak ortaya çıkabilir.
  • Ben States eklemek ve kaldırmak için talimat verir ne vermedi ve ne zaman bu soru için önemli değildir çünkü. Bununla birlikte, bu cevap durumunda, dikkate alınması gereken aşağıdaki nokta vardır. Yana Stateartık ile oluşturulması gerekir Caröncesinde yöneticinin yöntemini çağırarak için (maruz boş yapıcısı), addStateve removeStateyöntemler bir almak gerekmez Carve sadece onu okuyabilir state.car.
  • Gözlemciler varsayılan olarak gözlemlenebilir olana kayıt sırasına göre bildirilir. Farklı bir sipariş belirtilebilir.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.