디자인 패턴

워니·2024년 7월 24일

디자인 패턴 : 프로그램을 설계할 때 발생했던 문제점들을 객체 간의 상호 관계 등을 이용하여 해결할 수 있도록 하나의 '규약'으로 만들어 놓은 것

싱글톤 패턴(singleton pattern)

하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴. 보통 데이터베이스 연결 모듈에 많이 사용된다

장점과 단점

  • 장점 :
    - 하나의 인스턴스를 만들어 놓고 해당 인스턴스를 다른 모듈들이 공유해서 사용하기 때문에 인스턴스를 생성하는 비용이 줄어듦
  • 단점 :
    - 의존성이 높아질 수 있다.
    • TDD시 독립적인 인스턴스를 만들기 어렵다(TDD : 싱글톤 패턴은 미리 생성된 하나의 인스턴스를 기반으로 구현하는 패턴이므로, 서로 독립적이어야 하는 단위테스트를 만들기 어렵다)
class Singleton {
	private static class singleInstanceHolder {
    	private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
    	return singleInstanceHolder.INSTANCE;
    }
}

public class HelloWorld {
	public static void main(String[] args) {
    	Singleton a = Singleton.getInstance();
        Singleton b = Singleton.getInstance();
        if(a==b) System.out.println(true);
    }
}
// a==b이므로 true가 반환된다

팩토리 패턴(factory method)

객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화한 패턴.
상속 관계에 있는 두 클래스에서 상위 클래스가 중요한 뼈대를 결정하고, 하위 클래스에서 객체 생성에 관한 구체적인 내용을 결정하는 패턴.

enum coffeeType {
	LATTE,
    ESPRESSO
}

abstract class Coffee {
	protected String name;
    
    public String getName() {return name;}
}

class Latte extends Coffee {
	public Latte {name = "latte";}
}

class Espresso extends Coffee {
	public Espresso{name="espresso";}
}

class CoffeeFactory {
	public static Coffee createCoffee(CoffeeType type) {
    	switch(type) {
        	case LATTE: return new Latte();
            ase Espresso: return new Espresso();
            default: throw newe IllegalArgumentException("invalid coffee type: " + type);
        }
    }
}

public class Main {
	public static void main(String[] args) {
    	Coffee coffee = CoffeeFactory.createCoffee(CoffeeType.LATTE);
        System.out.println(coffee.getName()); // latte
    }
}

전략 패턴(strategy pattern)

객체의 행위를 바꾸고 싶은 경우 직접 수정하지 않고, '캡슐화된 알고리즘'을 컨텍스트 안에서 바꿔주면서 상호 교체가 가능하게 만드는 패턴

어떤 아이템을 살 때 LUNA Card로 사는 것과 KAKAOCard로 사는 것을 구현한 예제

interface PaymentStrategy{public void pay(int amount);}

class KAKAOCardStrategy implements PaymentStrategy {
	private String name;
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;
    
    public KAKAOCardStrategy(String name, String cardNumber, String cvv, String dayOfExpity){
    	this.name = name;
        this.cardNumber = cardNumber;
        this.cvv = cvv;
        this.dayOfExpity = dayOfExpity;
    }
    
    @Override
    public void pay(int amount) {System.out.println(amount + " paid usind KAKAOCard";}
}

class LUNACardStrategy implements PaymentStrategy {
	private String emailId;
    private String password;
    
    public LUNACardStrategy(String email, String password) {
    	this.emailId = emailId;
        this.password = password;
    }
    
    @Override
    public void pay(int amount) {System.out.println(amount + " paid using LUNACard");}
}

전략 패턴의 예시

전략 패턴을 활용한 라이브러리는 passport가 있다.

-> Node.js에서 인증 모듈을 구현할 때 쓰는 미들웨어 라이브러리로, 서비스 내 회원가입 방법과 페이스북/네이버 등 OAuth전략 등을 지원한다

옵저버 패턴(Observer pattern)

주체가 어떤 객체의 상태 변화를 관찰하다가 상태 변화가 있을 때마다 메서드 등을 통해 옵저버 목록에 있는 옵저버들에게 변화를 알려주는 디자인 패턴.
예시로는 트위터가 있다.

내가 어떤 사람인 주체를 '팔로워'한 상태라면, 주체가 포스팅을 올릴 때마다 알람이 '팔로워'에게 전달되야 한다
또한, 주로 이벤트 기반 시스템이나 MVC패턴에도 사용된다(주체인 model에 변경사항이 생겨 update()메서드로 옵저버인 view에 알려주고, 이를 기반으로 controller가 동작하는 방식)

interface Subject{
	public void register(Observer obj);
    public void unregister(Observer obj);
    public void notifyObservers();
    public Object getUpdate(Observer obj);
}

interface Observer {
	public void update();
}

class Topic implements Subject {
	private List<Observer> observers;
    private String message;
    
    public Topic() {
    	this.observers = observers;
        this.message = "";
    }
    
    @Override
    public void register(Observer obj) {
    	if(!observers.contain(obj)) observers.add(obj);
    }
    
    @Override
    public void unregister(Observer obj) {
    	observers.remove(obj)
    }
    
    @Override
    public void notifyObservers() {
    	this.observers.forEach(Observer::update);
    }
    
    @Override
    public void getUpdate(Observer obj) {
    	return this.message;
    }
    
    public void postMessage(String msg) {
    	this.message = msg;
        notifyObservers();
    }
}

class TopicSubscriber implements Observer {
	private String name;
    private Subject topic;
    
    public TopicSubscriber(String name, Subject topic) {
    	this.name = name;
        this.topic = topic;
    }
    
    @Override
    public void update() {
    	String msg = String.valueOf(topic.getUpdate(this));
    }
}
profile
매일, 조금씩 나아가는중

0개의 댓글