본문 바로가기

Java

람다 표현식을 활용한 디자인패턴 - 옵저버 패턴

디자인 패턴은 유용하다.

람다 표현식을 디자인 패턴에 적용한다면 더 간결하게 구현할 수 있다.

옵저버 패턴

어떤 이벤트가 발생했을 때 한 주체가되는 객체가 다른 옵저버가 되는 객체에게 알림을 보내야 하는 상황에 사용된다.

예를 들어 유튜브 구독자에게 알림이 가능 상황을 예시로 들 수 있겠다.

다음 예제에서는 주식시장에서 주식 가격에 따라 자동으로 주식을 사고 파는 상황을 간단하게 구현해 보겠다.

 

첫째로 주체가 되는 객체를 구현하면 다음과 같다.

1
2
3
4
public interface Subject {
    void registerObserver(Observer o);
    void notifyObservers(int money);
}
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class StockMarket implements Subject {
    private final List<Observer> observers = new ArrayList<>();
 
    @Override
    public void registerObserver(final Observer o) {
        this.observers.add(o);
    }
 
    @Override
    public void notifyObservers(final int money) {
        System.out.println("현재 주식가격은 : " + money);
        observers.forEach(o -> o.notify(money));
    }
}

 

그리고 주식시장을 관찰하는 옵저버객체를 구현해보자.

1
2
3
4
public interface Observer {
    void notify(int money);
}
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class BuyStock implements Observer {
    private final int buyPoint;
 
    public BuyStock(final int buyPoint) {
        this.buyPoint = buyPoint;
    }
 
    @Override
    public void notify(final int money) {
        if (money < buyPoint){
            System.out.println("주식을 구입했습니다");
        }
    }
}
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SellStock implements Observer{
    private final int sellPoint;
 
    public SellStock(final int sellPoint) {
        this.sellPoint = sellPoint;
    }
 
    @Override
    public void notify(final int money) {
        if (money > sellPoint){
            System.out.println("주식을 팔았습니다");
        }
    }
}

 

위의 코드를 실행하는 방법은 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Main {
    public static void main(String[] args) {
        StockMarket stockMarket =  new StockMarket();
        stockMarket.registerObserver(new SellStock(500));
        stockMarket.registerObserver(new BuyStock(300));
        stockMarket.notifyObservers(200);
        stockMarket.notifyObservers(300);
        stockMarket.notifyObservers(400);
        stockMarket.notifyObservers(500);
        stockMarket.notifyObservers(600);
 
        //출력 결과
//        현재 주식가격은 : 200
//        주식을 구입했습니다
//        현재 주식가격은 : 300
//        현재 주식가격은 : 400
//        현재 주식가격은 : 500
//        현재 주식가격은 : 600
//        주식을 팔았습니다
    }
}

 

 

람다 표현식 사용

 

위의 코드는 옵저버가 늘어날 수록 그에 해당하는 클래스를 추가 해주어야 하는 수고로움이 있다.

하지만 람다 표현식을 사용한다면 그 수고로움을 덜 수 있다.

람다 표현식을 사용하여 구현하면 다음과 같다.

 

먼저 주체가 되는 클래스구현까지는 동일하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public interface Subject {
    void registerObserver(Observer o);
    void notifyObservers(int money);
}
 
public class StockMarket implements Subject {
    private final List<Observer> observers = new ArrayList<>();
 
    @Override
    public void registerObserver(final Observer o) {
        this.observers.add(o);
    }
 
    @Override
    public void notifyObservers(final int money) {
        System.out.println("현재 주식가격은 : " + money);
        observers.forEach(o -> o.notify(money));
    }
}

 

여기서 옵저버를 명시적으로 인스턴스화 하지 않고 람다 표현식으로 직접 전달할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Main {
    public static void main(String[] args) {
        StockMarket stockMarket = new StockMarket();
        stockMarket.registerObserver((int money) -> {
            if (money > 500) {
                System.out.println("주식을 팔았습니다");
            }
        });
        stockMarket.registerObserver((int money) -> {
            if (money < 300) {
                System.out.println("주식을 구입했습니다");
            }
        });
        stockMarket.notifyObservers(200);
        stockMarket.notifyObservers(300);
        stockMarket.notifyObservers(400);
        stockMarket.notifyObservers(500);
        stockMarket.notifyObservers(600);
 
        //출력 결과
//        현재 주식가격은 : 200
//        주식을 구입했습니다
//        현재 주식가격은 : 300
//        현재 주식가격은 : 400
//        현재 주식가격은 : 500
//        현재 주식가격은 : 600
//        주식을 팔았습니다
    }
}

 

※ 람다 표현식을 사용하는 것이 항상 좋은 것은 아니다.

불필요한 코드를 제거할 수 있어서 람다 표현식이 유용할 수 있고, 경우에 따라 기존의 방식을 고수하는 것이 더 좋을 수 있다.

 

반응형