2016-06-03 6 views
0

Observer를 주제로 사용할 때 상황이 생깁니다. A와 B의 두 개의 엔테이트 A와 B가있는 이미지를 만듭니다. A의 모델에서 변경이 발생하면 다른 엔티티는 B (C, D ... 등)를 포함하여 알아야합니다.옵저버 패턴 무한 루프

B의 모델에서 변경이 발생하면 다른 엔테이트가 A (C, D ... 등)를 알아야합니다. 내가 무한 루프 betteween A를 얻을와 B가

는 관찰자 pattren가 제대로 implmented되지 않았거나 내가 디자인의이 종류를 처리하기 위해 다른 pattren 필요합니까 이런 식으로 옵저버 패턴을 implmenting으로

?

어떤 방법 그녀의 내 구현

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

BModel

수입 인 java.util.ArrayList; import 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); 
     } 
    } 
} 

다음은 컨트롤러

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

    } 
} 
+0

이 코드 예제는 모든 구문 오류를 해결할 때 무한 루프를 작성하지 않습니다. "B Changed"가 출력되고 종료됩니다. – explv

+0

데이터를 모델에로드하는 데 실패했습니다. 이제 무한 루프가 생기고 루프를 피하거나 pattren을 사용하여보다 적절한 모델을 사용하려고합니다. –

+1

왜 직접 패턴을 구현하고 있습니까? 즉, 자신의 인터페이스와 물건을 만드시겠습니까? 이 패턴에 필요한 인터페이스와 클래스는 이미 Java에서 구현됩니다. 즉, 클래스 'Observable' (클래스라는 이름에도 불구하고 관찰되는 객체) 및 인터페이스'Observer '입니다. –

답변

1

당신이 무한 루프를 얻고있는 이유는 당신마다 때문에 Observabl을 업데이트하십시오. e, 당신은 관찰자들에게 통보하지만,이 통보 프로세스는 모델을 다시 업데이트하므로 반복됩니다.

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

다음

당신이 찾고있는 방법에 옵저버 패턴을 사용하는 방법의 예입니다
0

@ arizzle의 대답은 효과가 있지만 Observer 패턴을 오용하고 있다고 생각합니다.

관찰자 한 개체 변경> 상태, 모든 종속 자동 통보 및 업데이트되면되도록

개체 간의 일대 종속성을 정의한다.

Source

귀하의 문제는 더 대다 관계처럼 보인다.이 경우 Mediator Pattern을 사용하여 이러한 복잡성을 숨기는 것이 좋습니다.

이 규범적인 UML 다이어그램은이 패턴입니다 :

Mediator 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" 

이 방법, 당신은 알 수 확실히 모두가 그것을 받았으므로 각 동료가 새로운 상태를 알리기 위해 다른 방송을 할 필요가 없습니다.

+0

나는 중재자 패턴을 사용하는 아이디어를 좋아하지만, 나는 여전히 모델의 변화에 ​​대해 GUI 구성 요소를 알리는 방법을 모른다. Gui Components에 알리기 위해 옵저버를 사용하고있었습니다. –

+0

아직도 모델이 다른 모델이 변경되었음을 알 필요가있는 이유를 이해하지 못합니다. 귀하의 모델은이 상황에서 "게시자"와 GUI 인 "가입자"여야합니다. GUI와 모델간에 1 : 1 관계가있는 경우 Observer 패턴이 더 적합합니다. 설명하는 방식에 따라 두 패턴을 혼합해야 할 수도 있습니다. –

+0

제 문제는 각 모델이 다른보기를 알리는 serval 모델입니다. 그래서, 저는 관측 가능하고 중재자 클래스에서 확장 할 수 없습니다. 이게 내 문제를 좀 더 명확히 밝히기를 바랍니다. –