BoostStudy / design-patterns

디자인 패턴의 아름다움 스터디 저장소
6 stars 0 forks source link

CHAPTER 8 행동 디자인 패턴 - 1 #9

Closed lee-ji-hoon closed 3 weeks ago

lee-ji-hoon commented 1 month ago

8-1. UserController 클래스는 여전히 스레드 풀을 생성하고 옵저버를 등록하는 등 옵저버 패턴과 관련된 비즈니스와 관련 없는 코드가 많이 남아있는데 어떻게 더 개선이 가능할까?

8-2. 프레임워크의 클래스가 두 개으 ㅣ템플릿 메서드를 노출하고 템플릿 메서드가 호출할 몇 개의 추상 메서드를 정의한다고 가정하면

public abstract class AbstractCalss {
    public final void templateMethod1() {
        method1();
        method2();
    }
}

하나만 사용하더라도 위 처럼 추상 메서드를 하위 클래스에 전부 구현해야 하는 문제가 있는데 어떻게 해야 할지

8-3. 콜백의 다른 응용 방법에는 어떤 것이 있을까

yangsooplus commented 1 month ago

8-1. 글쎄요.. 8-2. 프레임워크의 클래스니까 코드 수정이 불가하겠지? 메서드 1개만 사용하게 되는 클래스가 많다면 Wrapping 한번 해서 안 쓰는 추상 메서드는 빈 함수로 구현하고 사용할 메서드는 사용하는 곳에서 구현해서 사용하기? 8-3. 글쎄요..

lee-ji-hoon commented 1 month ago

8-2는 좋은 예시가 있다.

TextWatcher를 사용할때 대부분 onTextChaged 만 사용하고 싶음에도

public interface TextWatcher extends NoCopySpan {
    public void beforeTextChanged(CharSequence s, int start,
                                  int count, int after);

    public void onTextChanged(CharSequence s, int start, int before, int count);

    public void afterTextChanged(Editable s);
}

beforeTextChanged afterTextChanged 를 강제로 구현을 하게 한다. 그래서 TextView의 API 중에서

public inline fun TextView.addTextChangedListener(
    crossinline beforeTextChanged: (
        text: CharSequence?,
        start: Int,
        count: Int,
        after: Int
    ) -> Unit = { _, _, _, _ -> },
    crossinline onTextChanged: (
        text: CharSequence?,
        start: Int,
        before: Int,
        count: Int
    ) -> Unit = { _, _, _, _ -> },
    crossinline afterTextChanged: (text: Editable?) -> Unit = {}
): TextWatcher {
    val textWatcher = object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {
            afterTextChanged.invoke(s)
        }

        override fun beforeTextChanged(text: CharSequence?, start: Int, count: Int, after: Int) {
            beforeTextChanged.invoke(text, start, count, after)
        }

        override fun onTextChanged(text: CharSequence?, start: Int, before: Int, count: Int) {
            onTextChanged.invoke(text, start, before, count)
        }
    }
    addTextChangedListener(textWatcher)

    return textWatcher
}

이렇게 before과 after는 구현을 하지 않아도 되게끔 한 번 wrapping을 한 형태가 존재한다.

ldh019 commented 1 month ago

클래스나 객체 간의 상호 작용 문제를 해결하는 패턴

다른 디자인 패턴에 비해 개수가 많음

1. 옵서버 패턴

발행-구독 패턴이라고도 부름

일대일 의존 관계가 정의되어 있으면, 한쪽이 변경될 때 의존하고 있는 객체는 모두 알림을 받음

의존 대상이 되는 객체를 피관찰자, observable

의존하고 있는 객체를 관찰자, observer

보통 등록, 삭제, 알림 3가지의 기능을 기본적으로 사용

동기식 차단 옵저버 패턴

비동기식 비차단 옵저버 패턴

교차 프로세스 옵저버 패턴

EventBus 프레임워크

생각해보기

2. 템플릿 메서드 패턴

하나의 메서드 안에 정의된 비즈니스 논리의 틀

일부 작업 단계를 하위 클래스로 넘길 수 있음

일반적으로 공통되는 로직의 재사용을 위한 역할을 함

프레임워크의 확장을 지원하기 위한 역할로도 사용됨

메서드 콜 대신에 콜백을 사용해서도 구현할 수 있음

콜백을 사용할때 hooking을 많이 이용하기도 함

템플릿 메서드 VS 콜백

생각해보기 1

둘다 다 안쓰는 경우가 존재하면,, 애시당초에 그 클래스를 잘못 설계한게 아닐까…? 클래스를 두개로 나누면… 엄.. 음..