본문 바로가기

Software Architect

[Design Pattern] Observer Pattern

Observer Pattern

개요

  • 옵저버 또는 리스너라 불리는 하나 이상의 객체를 관찰 대상이 되는 객체에 등록
    -> 관찰 대상 객체가 발생시키는 이벤트를 받아 처리
  • 이벤트가 발생하면 각 옵저버는 Callback을 받음 
  • 활용사례
    > 이벤트 기반 프로그래밍

코드 구현

import java.util.ArrayList;

public class main {
	public static void main(String[] args) {
		Subject center = new Subject();
		
		Observer ob1 = new ObserverA();    // [1]
		Observer ob2 = new ObserverB();
		
		center.registerObservers(ob1);     // [2]
		center.registerObservers(ob2);
		
		center.pushButton();
	}
}

class Subject {
	ArrayList<Observer> obs = new ArrayList<Observer>();  // [3]
	
	public void registerObservers(Observer ob) {  
		this.obs.add(ob);
	}
	
	public void unregisterObservers(Observer ob) {
		this.obs.remove(ob);
	}
	
	public void notifyObservers() {                     // [4]
		for (int i = 0; i < obs.size(); i++) {
			obs.get(i).notifyO();
		}
	}
	
	public void pushButton() {
		System.out.println("User button is pressed!!");
		notifyObservers();
	}
}

interface Observer {
	void notifyO();
}

class ObserverA implements Observer {
	@Override
	public void notifyO() {
		System.out.println("- ObserverA is up!!");
	}
}
class ObserverB implements Observer {
	@Override
	public void notifyO() {
		System.out.println("- ObserverB is up!!");
	}
}
  • [1] Observer 생성
  • [2] Observer 등록
  • [3] Subject에서 Observer 등록시 Object를 저장하게 될 Array list
  • [4] Subject에서 이벤트 발생 시 등록된 전체 Object에 대해서 notify 전달

 

 

코드 구현 - (응용)

  • 유투브에서 구독하는 경우
    > 유투버가 구독자를 선택하는 경우 (위의 일반적인 패턴)
    > 구독자가 유투버를 선택하는 경우 (여기서 구현)
유투버가 구독자를 선택하는 경우 (일반적으로 그렇지 않음)

import java.util.ArrayList;

public class main {
	public static void main(String[] args) {
		Youtuber host = new Youtuber();
		
		Observer ob1 = new ObserverA();
		Observer ob2 = new ObserverB();
		
		// 유투버가 구독자를 선택
		//host.subsribe(ob1);
		//host.subsribe(ob2);
		
		// 구독자가 유투버 선택
		ob1.subscribe(host);
		ob1.subscribe(host);
		
		host.upload();
	}
}

class Youtuber {
	private ArrayList<Observer> obs = new ArrayList<Observer>();
	
	public void subsribe(Observer ob) {
		obs.add(ob);
	}
	
	void notis() {
		for (int i = 0; i < obs.size(); i++) {
			obs.get(i).noti();
		}
	}
	
	void upload() {
		System.out.println("영상 업로드 완료");
		notis();
	}
}

// 구독자
interface Observer {
	void noti(); 
	void subsribe(Youtuber); 
}

class ObserverA implements Observer {
	@Override
	public void noti() {
		System.out.println("- A 유튜브 alarm !!");
	}

	
}
class ObserverB implements Observer {
	@Override
	public void noti() {
		System.out.println("- B 유튜브 alarm !!");
	}	
}

-----------------------------------------------------------------------
(응용)
구독자가 유투버 선택하는 경우 

import java.util.ArrayList;

public class main {
	public static void main(String[] args) {
		Youtuber host1 = new Youtuber();
		Youtuber host2 = new Youtuber();
		
		Observer ob1 = new ObserverA();
		Observer ob2 = new ObserverB();
		
		// 유투버가 구독자를 선택
		//host.subsribe(ob1);
		//host.subsribe(ob2);
		
		// 구독자가 유투버 선택
		ob1.subscribe(host1);
		ob2.subscribe(host1);
		ob1.subscribe(host2);
		
		host1.upload();
		host2.upload();		
	}
}

class Youtuber {
	private ArrayList<Observer> obs = new ArrayList<Observer>();
	
	public void subsribe(Observer ob) {
		obs.add(ob);
	}	
	void notis() {
		for (int i = 0; i < obs.size(); i++) {
			obs.get(i).noti(this);
		}
	}
	
	void upload() {
		System.out.println(this+" 영상 업로드 완료");
		notis();
	}
}

// 구독자
interface Observer {
	void noti(Youtuber y); 
	void subscribe(Youtuber y);                         // 구독자가 subsribe 하도록 정의
}

class ObserverA implements Observer {
	@Override
	public void noti(Youtuber y) {
		System.out.println("- A 유튜브 alarm !!" + y);
	}
	public void subscribe(Youtuber y) {                 // 여기서 subscribe 하는 method를 호출
		y.subsribe(this);
	}
	
}
class ObserverB implements Observer {
	@Override
	public void noti(Youtuber y) {
		System.out.println("- B 유튜브 alarm !!" + y);
	}

	@Override
	public void subscribe(Youtuber y) {
		y.subsribe(this);
	}	
}

 

 

구현 예제 - 키보드 

import java.util.ArrayList;
import java.util.HashMap;

public class main {
	public static void main(String[] args) {
		OS os = new OS();
		Button btn1 = new Button("Button-1");
		Button btn2 = new Button("Button-2");
		
		// 버튼 추가
		os.addButton(btn1);
		os.addButton(btn2);
		
		// Observer 등록
		btn1.subscribe(new Obs());
		
		// 버튼 클릭
		os.pushButton(btn1);
	}
}

class OS {
	HashMap<String, Button> map = new HashMap<String, Button>();
	
	void addButton(Button btn) {
		
		if (map.containsKey(btn.getName())) {
			System.out.println("ERROR: 이미 등록된 버튼");
			return;
		}
		map.put(btn.getName(),  btn);
	}
	void pushButton(Button btn) {

		btn.userClick();
	}
}

class Button {
	private ArrayList<Observer> obs = new ArrayList<Observer>();
	private String name;
	Button(String name) {
		this.name = name;
	}
	
	void subscribe(Observer ob) {
		obs.add(ob);
	}
	String getName() {
		return name;
	}
	void userClick() {
		for (int i = 0; i < obs.size(); i++) {
			obs.get(i).noti();
		}
	}
}

interface Observer {
	void noti();
}
class Obs implements Observer {

	@Override
	public void noti() {
		// Button cliek되면 개발자가 작성해야 하는 코드
		System.out.println("버튼이 클릭되었습니다");
	}	
}