티스토리 뷰

Java

토비의봄#04. Reactive Programming 1

LichKing 2016. 12. 22. 09:46

Reactive Programming이라는건 영단어 뜻 그대로 무언가에 반응하는 프로그래밍이라는 것이다. 무언가에 반응한다는건 대표적으로 이벤트들이 존재할 것이고, 이에 대한 대표적인 디자인 패턴인 옵저버 패턴이 있다.


1. Duality

네이버 사전을 검색해보면 '이중성'이라는 단어로 나오며, 수학적인 용어로는 '쌍대성'이라고 한다. 꽤나 어려운 개념이니 글로 풀어쓰는것보다는 코드로 확인해보자.


List<String> list = Arrays.asList("a", "b", "c", "d", "e")

for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) {
System.out.println(iter.next());
}


크게 어려운것 없는 코드다. 문자열이 들어있는 리스트를 생성하고 그걸 가져와서(pull) 출력을 한다.

뭐 이걸 왜 주목해야하는지 이유조차 모를 아주 당연한 코드다. 이걸 옵저버 패턴(Observer Pattern)을 이용해 구현해보자.


public class Ob {
public static void main(String[] args) {
// Observable 생성
// 변화가 생겼을때 옵저버들에게 전파하는 역할
IntObservable ob = new IntObservable();

// Observer 객체
// Observable에게 등록되어 변화를 전파받는 역할
// Update 메서드내에 변화를 전파받았을때 처리할 내용을 구현해야함
Observer observer = new Observer() {
public void update(Observable o, Object arg) {
System.out.println(arg);
}
};
ob.addObserver(observer);
ob.run();
}
}

class IntObservable extends Observable implements Runnable{
public void run() {
List<String> list = Arrays.asList("a", "b", "c", "d", "e");

for(String str : list){
// 변화가 생겼다는걸 설정하는 메서드
// 해당 메서드를 호출하지않으면 변화가 없다고 보기떄문에 notify를 실행해도 전파되지않음
// protected 접근제어자이기때문에 동일패키지가 아닌이상 외부에서는 호출 불가능
setChanged();
// 변경내용을 전파하는 메서드
notifyObservers(str);
}
}
}


자바에서는 기본적으로 Observer Pattern을 위한 API를 제공하고있다. 때문에 처음부터 구현해도 되지만 해당 API를 이용할 수도있다. 자바 1.0부터 존재하던 API이기때문에 제네릭없이 Object를 그대로 전달받는 등의 옛날스타일(?)의 코드이다.

API에 대한 기본적인 설명은 주석을 달아놨으니 참고하기 바란다.


실행해보면 알겠지만 출력내용은 동일하다. 대표적인 Duality의 교본인데 옵저버 패턴은 Iterator처럼 필요한 데이터를 가져와서(pull) 출력을 하는게 아니라 필요한 데이터를 전달해서(push)해서 출력을 하게한다.


Runnable 인터페이스를 구현한 만큼 간단하게 멀티스레드형식의 코드를 추가하면 이렇게 된다.


public static void main(String[] args) {
// Observable 생성
// 변화가 생겼을때 옵저버들에게 전파하는 역할
IntObservable ob = new IntObservable();

// Observer 객체
// Observable에게 등록되어 변화를 전파받는 역할
// Update 메서드내에 변화를 전파받았을때 처리할 내용을 구현해야함
Observer observer = new Observer() {
public void update(Observable o, Object arg) {
System.out.println(Thread.currentThread().getName() + " :: " + arg);
}
};
ob.addObserver(observer);

ExecutorService service = Executors.newFixedThreadPool(1);
service.execute(ob);
service.shutdown();

System.out.println(Thread.currentThread().getName() + " :: hello world");
}


스레드 관련 코드는 2줄 추가됐고 스레드명칭을 확인하기 위한 코드가 약간 추가됐다.

간단하게 설명했지만 pull 방식과 push 방식의 차이가 리액티브 프로그래밍의 시발점이 되게되는것이다. 그럼 리액티브 프로그래밍은 옵저버 패턴이냐 라고 생각할 수 있는데, 옵저버 패턴이 원시적인 리액티브 프로그래밍이라고 볼 수 있다.

옵저버패턴에는 몇가지 문제가 있는데 그것들을 해소하고, 용어들을 바꾼게(ㅜㅜ) 요즘 뜨거운 감자로 부상하고있는 리액티브 프로그래밍이 되게된다.


1-1. Complete의 부재

특정 이벤트가 발생하면 Observable은 자신에게 등록된 Observer들에게 변경사항을 전파하게된다. 전달받은 옵저버들은 전달이 오면 그에 알맞는 처리를 하게된다. 하지만 이게 마지막 전파인지 알 수 있는 방법이 없다.


1-2. Error 처리

옵저버들이 자신이 해야할 일을 처리하다가 예외가 발생하는 경우는 충분히 존재할 수 있는데, 이를 옵저버블이 알 도리가 없다. 물론 예외가 발생할 수 있는 코드라면 옵저버 내에서 예외를 처리하겠지만 옵저버블에게 전달되어야하는 예외가 존재할 수 있는데 이를 명시적으로 전달받는 API가 없다.

공유하기 링크
TAG
댓글
댓글쓰기 폼