[컴퓨터공학]/[Design Pattern]

[Design Pattern] Observer pattern, 옵저버 패턴 - JAVA

딥러닝 도전기 2022. 9. 6. 13:46

[Design Pattern] Observer pattern, 옵저버 패턴

 

옵저버 패턴은 객체의 상태 변화를 관찰하는 관찰자(옵저버)들의 목록을 객체에 등록하여 상태 변화가 있을 떄마다 메서드를 통해 목록의 옵저버에게 통지하는 디자인 패턴이다. - Wikipedia

 


옵저버 패턴은 객체의 상태변화를 감지하는 옵저버가 객체의 상태변화가 있을 때 그와 연관된 객체들에게 알림을 보내는 디자인 패턴으로 행위 패턴에 포함됩니다.

 

  • Subject는 Observer를 등록, 해제와 변경이 있을 경우 Observer에게 알리는 기능을 합니다.
  • Observer는 updating interface를 가지고 있으며 Subject에서 변화가 있을 때 알림을 수신합니다. 모든 observers는 Observer 인터페이스를 implements해야하며 Subject가 알림을 보낼 때 작동하는 update() 메소드를 가지고 있습니다.
  • ConcreteSubject는 Subject 인터페이스를 implements 하며, 상태 변화가 발생했을 때 notifyObservers() 메소드를 사용하여 연결되어있는 observers에게 변경을 알립니다.
  • ConcreteObservers는 Observer 인터페이스를 implements 하며 각각의 observer는 concrete subject에 등록 및 해제합니다. 

 

예시를 통해 살펴보도록 하겠습니다.

예시 출처 - JAVA DESIGN PATTERNS : reusable solution to common problems (Java Code Geeks)

 

위의 예시는 ConcreteSubject인 CommentaryObject가 Subject와 Commentary를 implements하고, ConcreteObserver인 SMSUsers가 Observer를 implements 하는 예제입니다.

CommentaryObject는 실시간으로 스포츠 뉴스를 SMSUsers에게 전달하며, SMSUsers는 이 스포츠 뉴스를 구독하는 구독자 입니다.

 

우선 Subject부터 구현하도록 하겠습니다.

 

  • Subject interface
public interface Subject {
    public void subscribeObserver(Observer observer);
    public void unSubscribeObserver(Observer observer);
    public void notifyObservers();
    public String subjectDetails();
}

Subject 인터페이스는 위에서 말씀드린 것처럼 구독자를 등록 및 해제, 상태 변화 발생 시 알림의 세 가지를 수행해야 합니다.

subscribeObserver(Observer observer) 메소드는 observer를 등록 합니다.

unSubscribeObserver(Observer observer) 메소드는 observer를 해제 합니다.

notifyObservers() 메소드는 변화가 발생하면 옵저버에게 알리는 역할을 합니다.

 

다음으로 Observer입니다

 

  • Observer interface
public interface Observer {
    public void update(String desc);
    public void subscribe();
    public void unSubscribe();
}

update(String desc) 메소드는 observer가 등록되어있는 subject에 변경이 생겼을 때, 변경을 알리기 위해 호출됩니다. 

subscribe() 메소드는 자신을 subject에 등록할 때 사용됩니다.

unSubscribe() 메소드는 등록된 subject에서 등록 해제할 때 사용됩니다.

 

  • Commentary interface
public interface Commentary {
    public void setDesc(String desc);
}

위의 interface는 스포츠 경기의 실시간 상황을 commentary object에 업데이트 하는데 사용됩니다. interface principle을 준수하기 위해 위처럼 사용합니다. (단일 책임 원칙)

 

  • CommentaryObject
import java.util.List;
public class CommentaryObject implements Subject,Commentary{
    private final List<Observer>observers;
    private String desc;
    private final String subjectDetails;
    public CommentaryObject(List<Observer>observers,String subjectDetails){
        this.observers = observers;
        this.subjectDetails = subjectDetails;
    }
    @Override
    public void subscribeObserver(Observer observer) {
        observers.add(observer);
    }
    @Override
    public void unSubscribeObserver(Observer observer) {
        int index = observers.indexOf(observer);
        observers.remove(index);
    }
    @Override
    public void notifyObservers() {
        System.out.println();
        for(Observer observer : observers){
            observer.update(desc);
    	}
    }
    @Override
    public void setDesc(String desc) {
        this.desc = desc;
        notifyObservers();
    }
    @Override
    public String subjectDetails() {
        return subjectDetails;
    }
}

위의 CommentaryObject는 Commentary와 Subject를 implements하는 ConcreteSubject입니다.

observers를 List형태로 저장합니다.

 

  • SMSUsers
public class SMSUsers implements Observer{
    private final Subject subject;
    private String desc;
    private String userInfo;
    public SMSUsers(Subject subject,String userInfo){
        if(subject==null){
            throw new IllegalArgumentException("No Publisher found.");
        }
        this.subject = subject;
        this.userInfo = userInfo;
    }
    @Override
    public void update(String desc) {
        this.desc = desc;
        display();
    }
    private void display(){
        System.out.println("["+userInfo+"]: "+desc);
    }
    @Override
    public void subscribe() {
        System.out.println("Subscribing "+userInfo+" to "+subject.subjectDetails()+ ←-
        " ...");
        this.subject.subscribeObserver(this);
        System.out.println("Subscribed successfully.");
    }
    @Override
    public void unSubscribe() {
        System.out.println("Unsubscribing "+userInfo+" to "+subject.subjectDetails ←-
        ()+" ...");
        this.subject.unSubscribeObserver(this);
        System.out.println("Unsubscribed successfully.");
    }
}

위의 코드는 Observer를 implements하는 SMSUsers 코드입니다.

ConcreteObserver에 해당합니다.

 

 

반응형