전공 서적/해드퍼스트 디자인 패턴

태태개발일지 - 디자인패턴

태태코 2024. 10. 29. 11:12
반응형

전략 패턴

정의:

객체들이 할 수 있는 행위 각각에 대해 전략 클래스를 생성하고, 유사한 행위들을 캡슐화 하는 인터페이스를 정의하여,

객체의 행위를 동적으로 바꾸고 싶은 경우 직접 행위를 수정하지 않고 전략을 바꿔주기만 함으로써 행위를 유연하게 확장하는 방법을 말합니다.

 

이 책에선 오리로 예시를 든다.

public Class Duck{

	public quck(){};
	public fly(){};

}

 

 

이렇게 되면 Duck을 상속받는 class 들은 무조건 fly와 quck을 날아야하기 때문에, 장난감 오리는 날지도 못하고, 꽉 하지도 못하는 데 상속을 통해 그 기능을 가져야한다. 여기서 전략 패턴이 필요하다.

 

 그래서 이러한 행동을 클래스로 정의하는 것이 전략 패턴이다.

 

interface Fly{
	public fly();
}

 

 

interface quck{
	public quack();
}

 

이렇게 행동을 추상화 시키고, 이를 구현하여 처리하면 됩니다.

 

class toyquck implements quck{
	public quack(){
    	System.out.println("난 장난감 오리 꽉할줄 모름")
    };
}

 

 

이런식으로 하게되면 행동을 클래스로 갈아끼울 수 있기때문에, 유지보수가 쉬워지고, 객체지향적으로 바뀔 수 있다.

옵저버 패턴

객체의 상태 변화를 관찰하는 관찰자들, 즉 옵저버들의 목록을 객체에 등록하여 상태 변화가 있을 때마다 메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴이다.

 

1. 상태 변화가 여러 곳에 영향을 줄 때

  • 예를 들어, 데이터가 변경될 때 그것을 표시하는 여러 UI 요소들이 자동으로 업데이트되어야 하는 경우에 사용해. 이렇게 하면, 데이터가 바뀔 때마다 일일이 UI를 갱신하지 않고, 데이터만 바꿔도 UI들이 알아서 반응하게 할 수 있어.

예시: 날씨 애플리케이션에서 날씨 데이터가 바뀌면 여러 디스플레이 화면(스마트폰, 웹, TV 등)에 자동으로 업데이트될 때.

2. 객체 간의 결합도를 낮추고 싶을 때

  • 객체들이 서로 직접적으로 의존하지 않고, 느슨하게 결합(loose coupling) 되어 있어야 할 때 사용해. 옵저버 패턴을 사용하면 주제(Subject)와 관찰자(Observer)가 서로 독립적으로 존재할 수 있어서 유지보수가 쉬워.

예시: 게시판 시스템에서 새로운 게시물이 추가되면 이메일 알림, 앱 푸시 알림, SMS 알림 등 다양한 채널로 알림을 보내야 할 때. 채널들이 주제에 강하게 결합되어 있지 않으면 각각의 알림 방식을 쉽게 추가하거나 제거할 수 있어.

3. 한 객체의 상태 변화에 대한 알림이 필요한 객체가 여러 개일 때

  • 한 객체의 상태가 변할 때, 그 변화를 여러 객체에게 알려야 할 때 이 패턴이 유용해. 주제는 관찰자를 등록하고, 상태가 바뀔 때마다 자동으로 알려주기 때문에 여러 객체에게 일일이 알릴 필요가 없어.

예시: 주식 시장 애플리케이션에서 특정 주식의 가격이 변경될 때 여러 투자자들에게 알림을 보내는 상황.

4. 실시간으로 상태 변화를 감지해야 할 때

  • 상태 변화가 실시간으로 반영되어야 할 때, 옵저버 패턴을 사용해. 상태 변화가 있을 때마다 자동으로 알림을 보내기 때문에 실시간 업데이트가 가능해.

예시: 게임에서 플레이어의 점수나 상태가 변경될 때, 실시간으로 스코어보드나 다른 UI에 반영하는 경우.

5. 구독/발행 모델을 만들고 싶을 때

  • 옵저버 패턴은 **구독/발행 모델(Pub/Sub)**에도 자주 사용돼. 객체들이 주제에 "구독"하고, 주제가 변경될 때 "발행"하는 형태로 상태 변화를 통지할 수 있어.

예시: 뉴스 사이트에서 특정 주제에 대해 구독하고, 새로운 뉴스가 올라오면 이메일이나 알림으로 받아보는 경우.

 

코드 예시

// 주제 인터페이스
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// 관찰자 인터페이스
interface Observer {
    void update(float temperature, float humidity, float pressure);
}

// 주제 구현 클래스
class WeatherData implements Subject {
    private List<Observer> observers;
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData() {
        observers = new ArrayList<>();
    }

    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature, humidity, pressure);
        }
    }

    // 날씨 정보가 변경될 때 호출되는 메소드
    public void measurementsChanged() {
        notifyObservers();
    }

    // 날씨 정보 설정 메소드
    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
}

// 관찰자 구현 클래스
class CurrentConditionsDisplay implements Observer {
    private float temperature;
    private float humidity;

    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }

    public void display() {
        System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
    }
}

// 사용 예시
public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();

        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();
        weatherData.registerObserver(currentDisplay);

        // 날씨 정보 갱신
        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(82, 70, 29.2f);
    }
}

 

 

Spring에서는 옵저버 패턴을 사용하기 위해 **이벤트(Event)와 리스너(Listener)**를 많이 활용해. Spring Framework는 자체적으로 이벤트 처리 메커니즘을 제공하므로, 옵저버 패턴을 쉽게 구현할 수 있다.

 

EventListener에 대해서는 따로 독립적으로 글 하나를 쓰겠다.

 

 

반응형