시그마 삽질==six 시그마

옵저버 패턴(Observer Pattern) 본문

프로그래밍/디자인패턴

옵저버 패턴(Observer Pattern)

Ethan Matthew Hunt 2020. 4. 25. 10:01
'Java 객체 지향 디자인 패턴' 책을 구입하시길  추천드립니다.

책 구입을 원하시는분은 요기를 클릭하시면 됩니다.

하단의 내용은 제가 예전에 읽었던 내용을 요약 정리한 것입니다.

 

The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

Source: https://en.wikipedia.org/wiki/Observer_pattern

 

https://en.wikipedia.org/wiki/Observer_pattern#cite_note-6

 

옵서버 패턴은 데이터의 변경이 발생했을 경우 상대 클래스나 객체에 의존하지 않으면서 데이터 변경을 통보하고자할때 사용하는 패턴

 

성적을 출력하는 기능을 만들어보자

 

ScoreRecord :입력된 점수를 저장하는 클래스

DataSheetView: 점수를 목록형태로 출력하는 클래스

 

ScoreRecord는 DataSheetView 참조를 가지고 있어서 성적이 입력될 경우 update()메서드를 통해 DataSheetView에 통보

DataSheetView또한 ScoreRecord참조를 가지고 있어서 통보받으면 출력실행(this로 받는건 생략)

 

public class ScoreRecord {	
	private List<Integer> scores = new ArrayList<Integer>() ;
	private DataSheetView dataSheetView ;

	public void setDataSheetView(DataSheetView dataSheetView) {
		this.dataSheetView = dataSheetView ;
	}
	public void addScore(int score) {
		scores.add(score) ;
		
		dataSheetView.update() ;
	}
	public List<Integer> getScoreRecord() {
		return scores ;
	}
}


public class DataSheetView {
	private ScoreRecord scoreRecord ;
	private int viewCount ;
	
	public DataSheetView(ScoreRecord scoreRecord, int viewCount) {
		this.scoreRecord = scoreRecord ;
		this.viewCount = viewCount ;
	}
	public void update() {
		List<Integer> record = scoreRecord.getScoreRecord() ;	
		displayScores(record, viewCount);
	}
	private void displayScores(List<Integer> record, int viewCount) {
		System.out.print("List of " + viewCount + " entries: ") ;
		for ( int i = 0 ; i < viewCount && i < record.size() ; i ++ ) {
			System.out.print(record.get(i) + " ") ;
		}
		System.out.println() ;
	}
}

public class Client {
	public static void main(String[] args) {
		ScoreRecord scoreRecord = new ScoreRecord() ;
		DataSheetView dataSheetView = new DataSheetView(scoreRecord, 3) ;
		
		scoreRecord.setDataSheetView(dataSheetView) ;
		
		for (int index = 1 ; index <= 5 ; index ++ ) {
			int score = index * 10 ;
			System.out.println("Adding " + score) ;
			scoreRecord.addScore(score) ;
		}		
	}
}

 

만약 상기 코드에서 성적 최소/최대 값을 추가하고 싶다면?

 

하단과 같이 수정해야한다.

 

 

public class ScoreRecord {	
	private List<Integer> scores = new ArrayList<Integer>() ;	
	private List<DataSheetView> dataSheetViews = new ArrayList<DataSheetView>() ;
	private MainMaxView minMaxView ;
	
	public void addDataSheetView(DataSheetView dataSheetView) {
		dataSheetViews.add(dataSheetView) ;
	}

	public void setMinMaxView(MainMaxView minMaxView) {
		this.minMaxView = minMaxView ;
	}
	public void addScore(int score) {
		scores.add(score) ;	
		for ( DataSheetView dataSheetView: dataSheetViews )
			dataSheetView.update() ;
		minMaxView.update() ;
	}
	public List<Integer> getScoreRecord() {
		return scores ;
	}
}


public class MainMaxView {
	private ScoreRecord scoreRecord ;
	
	public MainMaxView(ScoreRecord scoreRecord) {
		this.scoreRecord = scoreRecord ;
	}
	public void update() {
		List<Integer> record = scoreRecord.getScoreRecord() ;
		
		displayMinMax(record);
	}
	private void displayMinMax(List<Integer> record) {
		int min =  Collections.min(record, null) ;
		int max =  Collections.max(record, null) ;	
		System.out.println("Min: " + min + " Max: " + max) ;
	}
}


public class DataSheetView {
	private ScoreRecord scoreRecord ;
	private int viewCount ;
	
	public DataSheetView(ScoreRecord scoreRecord, int viewCount) {
		this.scoreRecord = scoreRecord ;
		this.viewCount = viewCount ;
	}
	public void update() {
		List<Integer> record = scoreRecord.getScoreRecord() ;	
		displayScores(record, viewCount);
	}
	private void displayScores(List<Integer> record, int viewCount) {
		System.out.print("List of " + viewCount + " entries: ") ;
		for ( int i = 0 ; i < viewCount && i < record.size() ; i ++ ) {
			System.out.print(record.get(i) + " ") ;
		}
		System.out.println() ;
	}
}


public class Client {
	public static void main(String[] args) {
		ScoreRecord scoreRecord = new ScoreRecord() ;
		DataSheetView dataSheetView3 = new DataSheetView(scoreRecord, 3) ;
		DataSheetView dataSheetView5 = new DataSheetView(scoreRecord, 5) ;
		MainMaxView minMaxView = new MainMaxView(scoreRecord) ;
	
		scoreRecord.addDataSheetView(dataSheetView3) ;
		scoreRecord.addDataSheetView(dataSheetView5) ;
		scoreRecord.setMinMaxView(minMaxView) ;
	
		for (int index = 1 ; index <= 5 ; index ++ ) {
			int score = index * 10 ;
			System.out.println("Adding " + score) ;
			scoreRecord.addScore(score) ;
		}		
	}
}

 

ScoreRecord 클래스에 MainMaxView가 추가되면서 수정을 해야한다.

이러한 상황은 성적 변경을 새로운 클래스에 통보할 때마다 반복적으로 발생하게 된다.

문제 해결 핵심은 성적 통보 대상이 변경되더라도 ScoreRecord 클래스를 그대로 재사용 할수 있어야 한다는 것이다.

 

 

ScoreRecord의 기능

1. 통보 대상의 객체 참조 관리

2. 각 통보 대상인 객체의 upate메서드 호출

 

위 기능은 성적 변경뿐만아니라 임의의 데이터가 변경되었을때도 동일하게 발생하는 기능임

이런 공통기능을 상위 클래스 및 인터페이스로 일반화할 필요있음.

 

so ScoreRecord의 공통기능을 대신할 Subject라는 일반화된 클래스를 만들어서

1.구독에 관심있는 각 대상객체를 추상화한 Obeserver인터페이스를 객체 참조 필드로 둔다

2.성적 변경에 관심이 있는 대상객체를 관리(추가,제거,통보)한다

 

마지막으로 성적 변경 구독에 관심이 있는 대상객체는 Obeserver인터페이스를 구현한다

 

 

public interface Observer {
	abstract public void update() ;
}


public abstract class Subject {
	private List<Observer> observers = new ArrayList<Observer>() ;
	
	public void attach(Observer observer) {
		observers.add(observer) ;
	}	
	public void detach(Observer observer) {
		observers.remove(observer) ;
	}
	public void notifyObservers() {
		for ( Observer o : observers ) o.update() ;
	} 
}


public class ScoreRecord extends Subject {
	private List<Integer> scores = new ArrayList<Integer>() ;	

	public void addScore(int score) {
		scores.add(score) ;		
		notifyObservers() ;
	}
	public List<Integer> getScoreRecord() {
		return scores ;
	}
}


public class DataSheetView implements Observer {
	private ScoreRecord scoreRecord ;
	private int viewCount ;
	
	public DataSheetView(ScoreRecord scoreRecord, int viewCount) {
		this.scoreRecord = scoreRecord ;
		this.viewCount = viewCount ;
	}
	public void update() {
		List<Integer> record = scoreRecord.getScoreRecord() ;	
		displayScores(record, viewCount);
	}
	private void displayScores(List<Integer> record, int viewCount) {
		System.out.print("List of " + viewCount + " entries: ") ;
		for ( int i = 0 ; i < viewCount && i < record.size() ; i ++ ) {
			System.out.print(record.get(i) + " ") ;
		}
		System.out.println() ;
	}
}


public class MinMaxView implements Observer {
	private ScoreRecord scoreRecord ;
	
	public MinMaxView(ScoreRecord scoreRecord) {
		this.scoreRecord = scoreRecord ;
	}
	public void update() {
		List<Integer> record = scoreRecord.getScoreRecord() ;
		
		displayMinMax(record);
	}
	private void displayMinMax(List<Integer> record) {
		int min =  Collections.min(record, null) ;
		int max =  Collections.max(record, null) ;	
		System.out.println("Min: " + min + " Max: " + max) ;
	}
}



public class Client {
	public static void main(String[] args) {
		ScoreRecord scoreRecord = new ScoreRecord() ;
		DataSheetView dataSheetView3 = new DataSheetView(scoreRecord, 3) ;
		DataSheetView dataSheetView5 = new DataSheetView(scoreRecord, 5) ;
		MinMaxView minMaxView = new MinMaxView(scoreRecord) ;
	
		scoreRecord.attach(dataSheetView3) ;
		scoreRecord.attach(dataSheetView5) ;
		scoreRecord.attach(minMaxView) ;

		
		for (int index = 1 ; index <= 5 ; index ++ ) {
			int score = index * 10 ;
			System.out.println("Adding " + score) ;
			scoreRecord.addScore(score) ;
		}		
	}
}

 

'프로그래밍 > 디자인패턴' 카테고리의 다른 글

Facade pattern  (0) 2020.04.30
컴퍼지트 패턴(Composite pattern)  (0) 2020.04.24
데코레이터 패턴(Decorator pattern)  (0) 2020.04.24
스테이트 패턴(State pattern)  (0) 2020.04.24
전략 패턴(Strategy Pattern)  (0) 2020.04.24
Comments