ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Design Pattern] Observer Pattern 옵저버 패턴
    Study/Design Pattern 2021. 7. 28. 19:10

     

    여러 객체를 구현하면 객체끼리 의존 관계를 가지기도 합니다. 예를 들어 '오늘의 메뉴'라는 객체가 있고 학생들 객체가 있으면, 오늘의 메뉴 객체의 내용에 따라 학생들이 먹는 음식 또한 달라질 것입니다. 이처럼 의존성을 가지는 다른 객체들에게 변경 상황을 알릴 필요가 있는데 이때 사용되는 디자인 패턴이 옵저버 패턴입니다. 옵저버 패턴은 객체 사이에 일 대 다의 의존 관계를 정의해 두어, 어떤 객체의 상태가 변할 때 그 객체에 의존성을 가진 다른 객체들이 그 변화를 통지받고 자동으로 갱신될 수 있게 만듭니다.

     

     

     

    class TodayMenu {
        public String meal;
        public String soup;
        public String sideDish1;
        public String sideDish2;
    }
    public abstract Student{
        public void eat();
        public String allergy;
    }

    위와 같이 오늘의 메뉴를 저장하는 class와 Student 추상클래스가 존재하는 상황을 가정해보겠습니다. 학생 구성원은 Student 를 상속받아 구현될 것이고 eat 추상메소드도 구현할 것입니다. 그런데 만약 특정 음식에 알레르기가 있는 학생은 오늘의 메뉴에 해당 메뉴가 있다면 밥을 못 먹을것입니다. 이처럼 Student의 구현 클래스들은  TodayMenu 클래스에 의존성을 가질 것이고 TodayMenu 메뉴의 변경에 따라 eat 메소드의 실행도 바뀌어야 할 것입니다. 

     

     

    public interface Subject {
    	public void registerObserver(Observer o);
    	public void removeObserver(Observer o);
    	public void notifyObservers();
    }
    
    public interface Observer {
    	public void update(String meal, String soup, String sideDish1, String sideDish2);
    }

    그래서 위와 같이 구독의 대상이 될 Subject 인터페이스와 구독을 받을 Observer 인터페이스를 생성해주어 Subject의 변화를 Observer 객체들에게 알릴수 있도록 해줄 수 있습니다. 위 인터페이스로 직접 구현을 해보면 아래와 같습니다.

     

     

    public class TodayMenu implements Subject{
        private String meal;
        private String soup;
        private String sideDish1;
        private String sideDish2;
        private List<Observer> observers;
        
        public void setTodayMenu(String meal, String, soup, String s1, String s2){
        	this.meal = meal;
            this.soup = soup;
            this.sideDish1 = s1;
            this.sideDish2 = s2;
        }
        
        @Override
        public void registerObserver(Observer o){
        	observers.add(o);
        }
        
        @Override
        public void removeObserver(Observer o){
        	observers.remove(o);
        }
        
        @Override
        public void notifyObservers(){
        	for (Observer observer : observers) {
                 observer.update(meal, soup, sideDish1, sideDish2);
            }
        }
    }
    public class CheolSu extends Student implements Observer{
    	
        private bool canEat;
        
    	public setAllergy(String allergy){
        	this.allergy = allergy;
        }
        
        @Override
        public void eat(){
        	if(catEat){
            	System.out.println("냠냠냠냠냠");
            }
            else{
            	System.out.println("알러지때문에 오늘은 굶는다.");
            }
        }
        
        @Override
        public void update(String meal, String soup, String sideDish1, String sideDish2) {
            canEat = true;
            if(allergy.equals(meal)){
            	canEat = false;
            }
            if(allergy.equals(soup)){
            	canEat = false;
            }
            if(allergy.equals(sideDish1)){
            	canEat = false;
            }
            if(allergy.equals(sideDish2)){
            	canEat = false;
            }
    	}
    
    }

    TodayMenu 클래스는 멤버 변수로 옵저버 리스트를 두어 현재 구독하고있는 옵저버 객체들을 관리하고, 만약 클래스에 변경이 생기면 notifyObservers 메소드를 통해 알리는 것을 확인할 수 있습니다. 옵저버의 객체인 Cheolsu는 update 메소드를 통해 Subject의 변화를 받아오고 변화에 따라 멤버 변수인 canEat를 변경함으로써 eat 메소드의 동작을 제어합니다.

     

     

    이처럼 옵저버 패턴을 통해 실시간으로 한 객체의 변경사항을 다른 객체에 전파할 수 있으며, 느슨한 결합으로 시스템이 유연하고 객체 간의 의존성을 제거할 수 있습니다. (느슨한 결합이란 어느 두 객체가 서로 상호작용을 해도, 서로의 구현에 대해 구체적으로 모르는 것을 뜻합니다)

    하지만 너무 많이 과하게 사용하면, 상태 관리가 힘들 수 있고 데이터 배분에 문제 등 새로운 문제를 야기할 수 있으므로 주의 깊게 사용해야 합니다.

     

    댓글

Designed by Tistory.