디자인 패턴 - 2. 전략 패턴, 옵저버 패턴, 데코레이터 패턴

크리링·2024년 11월 16일
0

디자인패턴

목록 보기
2/5
post-thumbnail

전략 패턴

깃허브 코드
알고리즘 군을 정의하고 캡슐화해서 각각의 알고리즘 군을 수정해서 쓸 수 있게 해줍니다. 전략 패턴을 사용하면 클라이언트로부터 알고리즘을 분리해서 독립적으로 변경할 수 있습니다.

전략 패턴

알고리즘 군을 정의하고 캡슐화해서 각각의 알고리즘 군을 수정해서 쓸 수 있게 해줍니다. 전략 패턴을 사용하면 클라이언트로부터 알고리즘을 분리해서 독립적으로 변경할 수 있습니다.

Before

새로운 Duck과 기존의 Duck의 꽥꽥 소리와 나는 기능을 각기 다르게 적용하고 싶은데
기존 Duck의 서브클래스는 같은 꽥 소리를 내고, 똑같이 날 수 밖에 없습니다.



요구사항

MallardDuck : quack() X, fly() O
ReadHeadDuck : quack() O, fly() X
RubberDuck : quack() O (삐삐 소리 내야함), fly() X



디자인 패턴 적용 후

ex)

public class MallardDuck extends Duck {

	public MallardDuck() {
		quackBehavior = new MuteQuack();
		flyBehavior = new FlyWithWings();
	}

	@Override
	public void display() {
		System.out.println("mallard duck 입니다");
		introduce();
	}
}






옵저버 패턴

깃허브 코드

신문사 + 구독자 = 옵저버 패턴
(신문사는 주제, 구독자는 옵저버)
주제에서는 중요한 데이터를 관리하는데 데이터가 바뀌면 옵저버들에게 그 소식이 전달됩니다.

한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체에게 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다 의존성을 정의




Before

WeaterData는 온도, 습도, 기압 기상 관측값이 갱신될 때마다 measurementsChanged()
메소드를 호출해서 다른 인스턴스에 업데이트 해줍니다.



public void measurementsChanged() {
	float temperature = getTemperature();
	float humidity = getHumidity();
	float pressure = getPressure();

	concurrentConditionsDisplay.update(temperature, humidity, pressure);
	statisticsDisplay.update(temperature, humidity, pressure);
	forecastDisplay.update(temperature, humidity, pressure);
}



디자인 패턴 적용 후

public class WeatherData implements Subject {

	List<Observer> observers = new ArrayList<>();
	float temperature;
	float humidity;
	float pressure;

	public WeatherData() {}

	public float getTemperature() {
		return 32;
	}

	public float getHumidity() {
		return 50;
	}

	public float getPressure() {
		return 29;
	}

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

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

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

	public void measurementsChanged() {
		notifyObservers();
	}

	public void setMeasurements() {
		this.temperature = getTemperature();
		this.humidity = getHumidity();
		this.pressure = getPressure();
		System.out.println();
		measurementsChanged();
	}
}
public class ForecastDisplay implements Observer, Display {
	public float temperature;
	public float humidity;
	public float pressure;

	public ForecastDisplay() {
	}

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

	@Override
	public void display() {
		System.out.println();
		System.out.println("Forecast Display");
		System.out.println("Temperature: " + temperature);
		System.out.println("Humidity: " + humidity);
		System.out.println("Pressure: " + pressure);
		System.out.println();
	}
}



느슨한 결합

객체들이 상호작용할 수 있지만, 서로를 잘 모르는 관계
객체 사이의 상호의존성 최소화 -> 유연성이 좋아짐

  • 주제는 옵저버가 특정 인터페이스를 구현한다는 사실만 앎
  • 옵저버는 언제든지 새로 추가 가능
  • 새로운 형식의 옵저버를 추가할 때도 주제를 변경할 필요가 없음
  • 주제와 옵저버는 서로 독립적으로 재사용 가능
  • 주제나 옵저버가 달라져도 서로에게 영향을 미치지 않음




데코레이터 패턴

깃허브 코드

객체에 추가 요소를 동적으로 더할 수 있습니다. 데코레이터를 사용하면
서브클래스를 만들 때보다 훨씬 유연하게 기능을 확장할 수 있습니다.




Before

각각의 옵션을 단 메뉴들을 일일이 객체로 만들어주는 상황






디자인 패턴 적용 후

public abstract class Beverage {    // 음료
	String description = "Unknown Beverage";

	public String getDescription() {
		return description;
	}

	public abstract double cost();
}



public class Espresso extends Beverage {

	public Espresso() {
		this.description = "Espresso";
	}

	@Override
	public String getDescription() {
		return "Espresso";
	}

	@Override
	public double cost() {
		return 3000;
	}
}
public abstract class CondimentDecorator extends Beverage {     // 첨가물
	Beverage beverage;

	public abstract String getDescription();
}



public class Mocha extends CondimentDecorator {
	Beverage beverage;
	public Mocha(Beverage beverage) {
		this.beverage = beverage;
	}

	@Override
	public String getDescription() {
		return beverage.getDescription() + ", Mocha";
	}

	@Override
	public double cost() {
		return beverage.cost() + 1500;
	}
}
Beverage espresso = new Espresso();
espresso = new Whip(espresso);
System.out.println(espresso.getDescription() + " " + espresso.cost() + "원");

Beverage beverage = new HouseBlend();
beverage = new  Mocha(beverage);
beverage = new Whip(beverage);
System.out.println(beverage.getDescription() + " " + beverage.cost() + "원");



0개의 댓글