簡體   English   中英

觀察者模式無限循環

[英]Observer pattern infinite loop

我有一個觀察員也要成為主題的情況。 因此,讓我們與具有兩個實體A和B的圖像進行比較。當在A的模型中發生更改時,其他實體應該知道包括B(C,D ... Etc)。

當B的模型發生更改時,其他實體也應該知道,包括A(C,D ... Etc)。

通過以這種方式實現觀察者模式,我得到了A和B之間的無限循環。

觀察者模式是否被正確實施,還是我需要另一個模式來處理這種設計?

無論如何我的實現

public interface ISubject {
    public void registreObserver(IObserver obs);

    public void removeObserver(IObserver obs);

    public void notifyObservers();
}

和觀察者界面

public interface IObserver {
    public void update(ISubject subject);
}

該模型

import java.util.ArrayList;
import java.util.List;


public class AModel implements ISubject {

    private List<IObserver> listObservers = new ArrayList<>();
    @Override
    public void registreObserver(IObserver obs) {
        listObservers.add(obs);
    }

    @Override
    public void removeObserver(IObserver obs) {
        listObservers.remove(obs);
    }

    public void loadData(){
        notifyObservers();
    }

    @Override
    public void notifyObservers() {
        for (IObserver obv : listObservers) {
            obv.update(AModel.this);
        }
    }
}

B模型

導入java.util.ArrayList; 導入java.util.List;

public class BModel implements ISubject {

    private List<IObserver> listObservers = new ArrayList<>();
    @Override
    public void registreObserver(IObserver obs) {
        listObservers.add(obs);
    }

    @Override
    public void removeObserver(IObserver obs) {
        listObservers.remove(obs);
    }

     public void loadData(){
        notifyObservers();
    }


    @Override
    public void notifyObservers() {
        for (IObserver obv : listObservers) {
            obv.update(BModel.this);
        }
    }
}

A控制器

public class AController implements IObserver {

private AModel model;

public void setModel(AModel model) {
    this.model = model;
}

    @Override
    public void update(ISubject subject) {
        System.out.println(" A Changed");
       model.loadData();
    }
}

B控制器

public class BController implements IObserver {

private BModel model;

public void setModel(BModel model) {
    this.model = model;
}
    @Override
    public void update(ISubject subject) {
        System.out.println(" B Changed");
model.loadData();
    }
}

主程序

public class Main {

    public static void main(String[] args) {
        AModel aModel = new AModel();
        AModel bModel = new BModel();

        AController aController = new AController();
        aController.setModel(aModel);

        AController bController = new BController();
        bController.setModel(bModel);

        aModel.registreObserver(bController);
        bModel.registreObserver(aController);

        // Here the updates starts a notify b and b notify a and so on 
        aModel.notifyObservers();

    }
}

之所以會出現無限循環,是因為每次更新Observable時,都會通知其觀察者,但是此通知過程隨后會再次更新模型,因此它會重復。

這是一個如何以尋找方式使用觀察者模式的示例:

import java.util.Observable;
import java.util.Observer;

public class Example {

    public static void main(String[] args) {

        Model modelA = new Model();
        Model modelB = new Model();

        Observer aController = (observable, arg) -> {
            System.out.println("A controller: " + arg);
        };

        Observer bController = (observable, arg) -> {
            System.out.println("B controller: " + arg);
        };

        modelA.addObserver(bController);
        modelB.addObserver(aController);

        modelA.update("test");
        modelB.update("test2");
    }
}

class Model extends Observable {

    private String data;

    public void update(String data) {
        this.data = data;
        setChanged();
        notifyObservers(data);
    }
}

輸出:

B控制器:測試

控制器:test2

盡管@arizzle的答案有效,但我認為您正在濫用Observer模式。

觀察者

在對象之間定義一對多依賴關系,以便當一個對象更改>狀態時,將自動通知和更新其所有依賴關系。

資源

您的問題似乎更像是多對多關系。 在這種情況下,我建議您使用Mediator Pattern隱藏這種復雜性。

這是此模式的經典UML圖:

調解員UML

在這里,我將跳過接口/抽象類的定義,以避免誇大答案。

基本實現:

class Mediator {
    private Map<String, Colleague> participants = new HashMap<String, Colleague>();
    public void register(Colleague c) {
        participants.put(c.getName(), c);
        c.setMediator(this);
    }

    public void send(Colleague from, String message, String to) {
        Colleague c = participants.get(to);
        if (c != null && c != from) {
            c.receive(message, from);
        }
    }

    public void send(Colleague from, String message) {
        for (Map.Entry<String, Colleague> e: participants.entrySet()) {}
            Colleague c = e.getValue();
            if (c != from)) {
                c.receive(message, from);
            }
        }
    }
}

abstract class Colleague {
    private Mediator mediator;
    private String name;

    public Colleague(String name) {
        this.name = name;
    }

    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    public void send(String msg, String to) {
        this.mediator.send(this, msg, to);
    }

    public void send(String msg) {
        this.mediator.send(this, msg);
    }

    abstract public void receive(String msg, Colleague from);
}

class ConcreteColleague1 {
    public void receive(String msg, String from) {
        // do something
        System.out.println("Received msg: " + msg + " from: " + from.getName());
    }
}

class ConcreteColleague2 {
    public void receive(String msg, String from) {
        // do other thing
        System.out.println("Received msg: " + msg + " from: " + from.getName());
    }
}

使用它:

Mediator m = new Mediator();

Colleague c1 = new ConcreteColleague1('foo');
Colleague c2 = new ConcreteColleague2('bar');
Colleague c3 = new ConcreteColleague1('baz');

c1.send("test");
c2.send("test");
c3.send("test");

將打印:

 "Received msg: test from: foo" "Received msg: test from: foo" "Received msg: test from: bar" "Received msg: test from: bar" "Received msg: test from: baz" "Received msg: test from: baz" 

這樣,當您廣播一條消息時,您可以確定每個人都收到了該消息,因此您無需為每個同事進行另一次廣播來傳達新狀態。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM