1. 옵저버 패턴이란?

  • 어떤 객체의 상태가 변할 때 그와 연관된 객체들에게 알림을 보내는 디자인 패턴
  • 야자시간에 밖에서 선생님이 오는지 살펴보는 학생을 생각하면 이해가 쉬움

 


 

2. 옵저버 패턴의 예시

Apple 제품을 사용하고 있는 사람들에게 공지사항(이벤트 발생)을 알려주는 시스템이다.

User 클래스

public class User {
	public String name;
    
	public void getMsg(String msg) {
		System.out.println(this.name + "가 메세지 수신: " + msg);
	}
}

사용자 Minsoo, Cheolsu 클래스

public class Minsoo extends User {
	public Minsoo(String name) {
		this.name = name;
	}
}

public class Cheolsu extends User {
	public Cheolsu(String name) {
		this.name = name;
	}
}

Apple 클래스 (옵저버(여기서는 User)들에게 알림을 전달)

import java.util.ArrayList;
import java.util.List;

public class Apple {
	public ArrayList<User> users = new ArrayList<User>();

	// 애플 알림을 구독하는 사람 추가
	public void subscribe(User user) {
		users.add(user);
	}

	// 애플 알림을 구독취소한 사람은 명단에서 제거
	public void unsubscribe(User user) {
		users.remove(user);
	}

	public void notice(String msg) {
		for (User user: users) {
			user.getMsg(msg);
		}
	}
}

Main 클래스

public class Main {
	public static void main(String[] args) {
		Apple apple = new Apple();
		Minsoo minsoo = new Minsoo("민수");
		Cheolsu cheolsu = new Cheolsu("철수");
		
		apple.subscribe(minsoo);
		apple.subscribe(cheolsu);
        // 민수, 철수가 애플 구독
		
		String msg = "아이폰미니 출시";
		apple.notice(msg);
		
		apple.unsubscribe(cheolsu);
        // 철수가 애플 구독취소
        
		msg = "아이폰12 출시";
		apple.notice(msg);
	}
}

// 출력
// 민수가 메세지 수신: 아이폰미니 출시
// 철수가 메세지 수신: 아이폰미니 출시
// 민수가 메세지 수신: 아이폰12 출시

'디자인 패턴 > 행위 패턴' 카테고리의 다른 글

전략 패턴 (Strategy Pattern)  (0) 2021.08.28

1. 데코레이터 패턴이란?

  • 객체의 결합을 통해 기능을 동적으로 유연하게 확장할 수 있게 해주는 패턴
  • 추가 기능의 조합을 설계하는 패턴

 


 

2. 데코레이터 패턴 예시

IPhone 시리즈 중 IPhoneSE는 500달러, IPhoneMini는 400달러라고 가정하자(또한 기본 시리즈를 iPhone이며, 이는 300달러라고 가정). 다음 예시는 Decorator 패턴을 통해 두 시리즈의 가격을 알려주는 예시이다.

Phone 인터페이스

public interface Phone {
	public void showPrice();
}

IPhone 클래스

public class IPhone implements Phone {
	public int price;
    
	public IPhone(int price) { this.price = price; }

	@Override
	public void showPrice() {
		System.out.println("iPhone: $" + this.price);
	}
}

IPhone을 꾸며주는 IPhoneDecorator

public class IPhoneDecorator implements Phone {
	public Phone iPhone;
	public String name;
	public int price;

	public IPhoneDecorator(Phone iPhone, String name, int price) {
		this.iPhone = iPhone;
		this.name = name;
		this.price = price;
	}

	@Override
	public void showPrice() {
		System.out.println(name + ": $" + this.price);
	}
}

IPhoneDecorator를 상속받는 IPhoneSE, IPhoneMini 클래스

public class IPhoneSE extends IPhoneDecorator {
	public IPhoneSE(Phone iPhone, String name) {
		super(iPhone, name, 500);
	}
}

public class IPhoneMini extends IPhoneDecorator {
	public IPhoneMini(Phone iPhone, String name) {
		super(iPhone, name, 400);
	}
}

Main 클래스

public class Main {
	public static void main(String[] args) {
		Phone iPhone = new IPhone(300);
		iPhone.showPrice();
	
		// iPhoneSE
		Phone iPhoneSE = new IPhoneSE(iPhone, "iPhoneSE");
		iPhoneSE.showPrice();
		
		// iPhoneMini
		Phone iPhoneMini = new IPhoneMini(iPhone, "iPhoneMini");
		iPhoneMini.showPrice();
	}
}

// 출력
// iPhone: $300
// iPhoneSE: $500
// iPhoneMini: $400

 

'디자인 패턴 > 구조 패턴' 카테고리의 다른 글

프록시 패턴 (Proxy Pattern)  (0) 2021.08.28
파사드 패턴 (Facade Pattern)  (0) 2021.08.27
어댑터 패턴 (Adapter Pattern)  (0) 2021.08.26

1. 프록시 패턴이란?

  • 실제 기능을 수행하는 객체 대신 가상의 객체를 사용해 로직의 흐름을 제어
  • 어떤 객체를 사용하고자 할 때 해당 객체를 대행하는 객체를 통해 대상 객체에 접근
  • 흐름제어만 할 뿐 결과값을 조작하거나 변경시키면 안됨

 


 

2. 프록시 패턴 예시

Phone 인터페이스

public interface Phone {
	public String turnOn();
}

IPhone 클래스

public class IPhone implements Phone {
	@Override
	public String turnOn() {
		return "IPhone turn on";
	}
}

PhoneProxy 클래스

public class PhoneProxy implements Phone {
	Phone iPhone;

	@Override
	public String turnOn() {
		System.out.println("Proxy 거쳐감");

		iPhone = new IPhone();
		return iPhone.turnOn();
	}
}

Main 클래스

public class Main {
	public static void main(String[] args) {
		Phone proxy = new PhoneProxy();
		System.out.println(proxy.turnOn());
	}
}

// 출력
// Proxy 거쳐감
// IPhone turn on

 

인터페이스를 중간에 두어 구체클래스들에게 영향을 받지 않게 설계하였으며, 직접 접근하지 않고 Proxy를 통해 한번 더 우회해서 접근하도록 구현되어 있다. 이를 통해 OCP, DIP 설계 원칙을 지킬 수 있다.

1. 팩토리 메서드 패턴이란?

  • 부모 클래스에 알려지지 않은 구체 클래스를 생성하는 패턴
  • 자식 클래스가 어떤 객체를 생성할지 결정하도록 하는 패턴
  •  객체를 생성하기 위해 인터페이스를 정의하지만, 어떤 클래스의 인스턴스를 생성할지에 대한 결정은 서브 클래스가 내리도록 한다.

 


 

2. 팩토리 메서드 패턴 예시

Phone 인터페이스

public interface Phone {
	void turnOn();
}

IPhone 클래스

public class IPhone implements Phone {
	@Override
	public void turnOn() {
		System.out.println("IPhone turn on");
	}
}

Galaxy 클래스

public class Galaxy implements Phone {
	@Override
	public void turnOn() {
		System.out.println("Galaxy turn on");
	}
}

PhoneFactory 클래스

public class PhoneFactory {
	public static Phone getPhone(String company) {
		if ("Apple".equalsIgnoreCase(company)) retrn new IPhone();
		else if ("Samsung".equalsIgnoreCase(company)) retrn new Galaxy();

		return null;
	}
}

getPhone 메서드를 이용하여 Phone의 서브클래스에 대한 정보를 알지 못한 채 인스턴스를 생성할 수 있게 된다.

 

Main 클래스

public class Main {
	public static void main(String[] args) {
		Phone iPhone = PhoneFactory.getPhone("Apple");
		Phone galaxy = PhoneFactory.getPhone("Samsung");

		iPhone.turnOn();
		galaxy.turnOn();
	}
}

// 출력
// IPhone turn on
// Galaxy turn on

'디자인 패턴 > 생성 패턴' 카테고리의 다른 글

싱글톤 패턴 (Singleton Pattern)  (0) 2021.08.26

1. 전략 패턴이란?

  • 실행 중에 알고리즘을 선택할 수 있게 하는 행위 소프트웨어 디자인 패턴
  • 특정한 계열의 알고리즘들을 정의하고 각 알고리즘을 캡슐화

 


 

2. 전략 패턴의 예시

아이폰은 애플스토어, 갤럭시는 구글플레이스토어(줄여서 플레이스토어)를 사용한다.
이를 이용해 간단한 예시를 만들어 보았다.

1) 전략 패턴을 적용하지 않은 경우

스토어 인터페이스

public interface Store {
	public void store();
}

아이폰 클래스

public class IPhone implements Store {
	public void store() {
		System.out.println("Appstore On");
	}
}

갤럭시 클래스

public class Galaxy implements Store {
	public void store() {
		System.out.println("PlayStore On");
	}
}

메인 클래스

public class Main {
	public static void main(String[] args) {
		Store iPhone = new IPhone();
		Store galaxy = new Galaxy();

		iPhone.store();
		galaxy.store();
	}
}

// 출력
// AppStore On
// PlayStore On

만약 애플에서 삼성을 인수하여, 이제 갤럭시에서도 애플스토어를 쓴다고 가정하자. 그렇게 되면 Galaxy의 store() 메서드를

System.out.println("AppStore On");

로 바꿔주면 되지만, 이는 개방 폐쇄의 원칙에 어긋나며, 확장이 될 경우 유지보수를 어렵게 한다. 따라서 이럴 경우 전략 패턴을 적용하면 문제를 해결할 수 있다.

 

2. 전략 패턴을 적용한 경우

스토어를 이용하는 두 가지 경우를 클래스로 생성하며, store()를 이용하여 어떤 스토어를 이용하는지 구현한다.

스토어 인터페이스

public interface Store {
	public void store();
}

앱스토어 클래스

public class AppStore implements Store {
	public void store() {
		System.out.println("AppStore On");
	}
}

플레이스토어 클래스

public class PlayStore implements Store {
	public void store() {
		System.out.println("PlayStore On");
	}
}

myStore 클래스

 

public class MyStore {
	private Store myStore;

	public void store() {
		myStore.store();
	}

	public void setStore(Store myStore) {
		this.myStore = myStore;
	}
}

IPhone, Galaxy 클래스

public class IPhone extends MyStore {

}

public class Galaxy extends MyStore {

}
이제 IPhone에서는 앱스토어를, Galaxy에서는 플레이스토어를 이용할 수 있도록 구현한다.

Main 클래스

public class Main {
	public static void main(String[] args) {
		MyStore iPhone = new IPhone();
		MyStore galaxy = new Galaxy();

		iPhone.setStore(new AppStore());
		galaxy.setStore(new PlayStore());
        
		iPhone.store();
		galaxy.store();
	}
}

아까 상황과 같이 애플이 삼성을 인수하여 갤럭시에서 앱스토어를 사용한다고 가정하면, setStore 메서드를 이용하여 수정하기만 하면 된다.

galaxy.setStore(new AppStore());
galaxy.store();

'디자인 패턴 > 행위 패턴' 카테고리의 다른 글

옵저버 패턴 (Observer Pattern)  (0) 2021.08.29

1. 파사드 패턴이란?

  • 소프트웨어의 다른 코드 부분에 대하여 간략화된 인터페이스를 제공
  • 퍼사드 객체는 복잡한 소프트웨어 바깥쪽의 코드가 라이브러리의 안쪽 코드에 의존하는 일을 감소시킴

 


 

2. 파사드 패턴의 예시

1. IPhone 클래스

public class IPhone {
	public void powerOn() {
		System.out.println("IPhone turn on");
	}
}

2. Galaxy 클래스

public class Galaxy {
	public void powerOn() {
		System.out.println("Galaxy turn on");
	}
}

3. PhoneFacade 클래스

public class PhoneFacade {
	private IPhone iPhone;
	private Galaxy galaxy;
    
	public PhoneFacade() {
		iPhone = new IPhone();
		galaxy = new Galaxy();
	}
    
	public void turnOn() {
		iPhone.powerOn();
		Galaxy.powerOn();
	}
}

4. Main 클래스

public class Main {
	public static void main(String[] args) {
		PhoneFacade phoneFacade = new PhoneFacade();
		phoneFacade.turnOn();
	}
}

// 출력
// IPhone turn on
// Galaxy turn on

 

PhoneFacade는 IPhone과 Galaxy를 캡슐화하여 turnOn() 메서드만 이용할 수 있고, 그 내부의 모습은 알 수 없다. 이 때, IPhone, Galaxy 객체를 생성하여 각자 powerOn() 메서드를 실행시키는 것이 아닌, PhoneFacade 클래스의 turnOn() 메서드를 통해 powerOn() 메서드를 실행시킨다.

+ Recent posts