헤드퍼스트 디자인 패턴 1장 | 디자인 패턴 소개와 전략 패턴
(에릭 프리먼 외 4인, 서환수 옮김, 한빛미디어)
기상 스테이션용 코드 추가하기
public class WeatherData {
// 인스턴스 변수 선언
public void measurementsChanged() {
float temp = getTemerature();
float humidity = getHumidity();
float pressure = getPressure();
currentConditionDisplay.update(temp, humidity, pressure);
statisticsDisplay.update(temp, humidity, pressure);
forecastDisplay.update(temp, humidiy, pressure);
}
// 기타 메소드
}
WeatherData에 있는 게터 메소드를 호출해서 최신 측정값을 가져옵니다. 각 값을 적당한 변수에 저장합니다.
각 디스플레이를 갱신합니다. 최신 측정값을 전달하면서 각 디스플레이 항목의 update 메소드를 호출합니다.
- 78p
- 79p
신문사 + 구독자 = 옵저버 패턴
- 81p
신문사를 주제(subject), 구독자를 옵저버(observer)라고 부른다는 것만 외워두세요.
- 81p
옵저버 패턴은 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체에게 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다 의존성을 정의합니다.
- 87p
옵저버 패턴에서는 주제가 상태를 저장하고 제어합니다. 따라서 상태가 들어있는 객체는 하나만 있을 수 있습니다. 반면에 옵저버는 상태를 사용하지만, 반드시 소유할 필요는 없습니다. 따라서 옵저버는 여러 개가 있을 수 있으며, 주제에서 상태가 바뀌었다는 사실을 알려주길 기다리는, 주제에 의존적인 성질을 가지게 되죠. 그러므로 하나의 주제와 여러 개의 옵저버가 연관된 일대 다 관계가 성립됩니다.
- 88p
데이터의 주인은 주제입니다. 옵저버는 데이터가 변경되었을 때 주제에서 갱신해 주기를 기다리는 입장이기에 의존성을 가진다고 할 수 있습니다. 이런 방법을 사용하면 여러 객체가 동일한 데이터를 제어하는 방법보다 더 깔끕한 객체지향 디자인을 만들 수 있습니다.
- 88p
디자인 원칙 : 상호작용하는 객체 사이에는 가능하면 느슨한 결합을 사용해야 한다.
- 90p
기상 스테이션 구현하기
인터페이스
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o); => 이 2가지 메소드는 observer를 인자로 받습니다. 각각 옵저버를 등록하고 제거하는 역할을 하죠.
public void notifyObservers(); => 주제의 상태가 변경되었을 때 모든 옵저버에게 변경 내용을 알리려고 호출
}
public interface Observer {
public void update(float temp, float humidity, float pressure);
}
=> 옵저버 인터페이스는 모든 업저버 클래스에서 구현해야 합니다.
따라서 모든 옵저버는 update() 메소드를 구현해야 합니다.
public interface DisplayElement {
public void display();
}
=> DisplayElement 인터페이스에는 display()라는 메소드밖에 없습니다. 디스플레이 항목을 화면에 표시해야 하면 그 메소드를 호출합니다.
subject 인터페이스 구현하기
public class WeatherData implements Subject {
private List<Observer> observers;
private float tempeerature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<Observer>();
}
=> 옵저버 생성자 = 객체 위에 추가한 리스트 객체 생성
public void registerObserver(Observer o) { => 옵저버가 등록을 요청하면 목록 맨뒤에 추가
observers.add(o);
}
public void removeObserver(Observer o) { => 탈퇴를 요청하면 목록에서 빼기
observers.remove(o);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
=> 정말 중요한 부분입니다.
모든 옵저버에게 상태 변화를 알려주는 부분이죠.
모두 Observer 인터페이스를 구현하는, 즉 update() 메소드가 있는 객체들이므로 손쉽게 상태 변화를 알려 줄 수 있습니다.
public void measurementsChanged() {
notifyObservers();
} => 기상 스테이션으로부터 갱신된 측정값을 받으면 옵저버들에게 알립니다.
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
- 94 ~ 95p
디스플레이 요소 구현하기
public class CurrentConditionDisplay implements Observer, DisplayElement { => weahterData 객체로부터 변경사항을 받으려면 Observer를 구현해야 합니다.
private float temperature;
private float humidity;
private WeahterData weahterData;
public CurrentConditionsDisplay(Weatherdata weatherDAta) { => 생성자에 weatherData라는 주제가 전달되며, 그 객체를 써서 디스플레이를 옵저버로 등록합니다.
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity; => update()가 호출되면 온도와 습도를 저장하고 display()를 호출합니다.
display();
}
public void display();
sout("현재 상태: 온도" + temperature + "F, 습도" + humidity ");
} => display()메소드는 가장 최근에 받은 온도와 습도를 출력합니다.
}
- 96p
Q. update() 메소드에서 display() 메소드를 호출하는 방법이 정말 최선인가요?
A. 지금 다루고 있는 간단한 예제에서는 값이 바뀔 때마다 display()를 호출하는 방법이 괜찮아 보입니다. 하지만 최선의 방법은 아닙니다. 데이터를 화면에 표시하는 더 좋은 방법은 12장에서 모델-뷰-컨트롤러 패턴을 배울 때 자세히 알아보도록 하죠.
- 96p
기상스테이션 테스트
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData(); => 우선 WeatherData 객체를 생성합니다.
CurrentConditionDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f); => 새로운 기상 측정값이 들어왔다고 가정
}
}
- 97p
주제가 옵저버로 데이터를 보내는 푸시(push)를 사용하거나 옵저버가 주제로부터 데이터를 당겨오는 풀(pull)을 사용하는 방법 중 어느 하나를 선택하는 일은 구현 방법의 문제라고 볼 수 있습니다. 하지만 대체로 옵저버가 필요한 데이터를 골라서 가져가도록 만드는 방법이 더 좋습니다. 시간이 지남에 따라 애플리케이션은 계속 바뀌고 점점 복잡해집니다. ... 옵저버가 필요한 데이터를 당겨올 수 있도록 기상 스테이션 코드를 수정하는 일은 그리 어렵지 않습니다. 주제가 자신의 데이터에 관한 게터 메소드를 가지게 만들고 필요한 데이터를 당겨올 때 해당 메소드를 호출할 수 있도록 옵저버를 고쳐주기만 하면 됩니다.
- 104p
풀 방식으로 코드 바꾸기
1) 주제에서 알림 보내기 : 옵저버의 update 메소드를 인자 없이 호출하도록 WeatherData의 notifyObservers() 메소드를 수정합니다.
2) 옵저버에게 알림 받기 : Observer 인터페이스에서 update() 메소드에 매개변수가 없도록 서명을 바꿔 줍니다.
3) 마지막으로 update() 메소드의 서명을 바꾸고 WeatherData의 게터 메소드로 주제의 날씨 데이터를 가져오도록 각 Observer 구상 클래스를 수정합니다.
- 105p
'Book' 카테고리의 다른 글
[독서 기록] 헤드퍼스트 디자인 패턴 4장 | 팩토리 패턴 - 객체지향 빵 굽기 (0) | 2022.11.14 |
---|---|
[독서 기록] 헤드퍼스트 디자인 패턴 3장 | 객체 꾸미기 - 데코레이터 패턴 (0) | 2022.11.14 |
[독서 기록] 헤드퍼스트 디자인 패턴 1장 | 디자인 패턴 소개와 전략 패턴 (에릭 프리먼, 엘리자베스 롭슨, 케이시 시에라, 버트 베이츠 지음, 서환수 옮김, 한빛미디어) (1) | 2022.11.14 |
[독서 기록] 클린 코드 11장, 12장 , 13장 외 / 시스템, 창발성, 동시성 (1) | 2022.11.13 |
[독서 기록] 클린 코드 9장, 10장 / 단위 테스트, 클래스 (0) | 2022.11.09 |