팩토리 메서드에 대하여
팩토리 메서드가 해결하려는 문제, 접근은 타당한가, 반례에 대하여
이 글의 목차

도서 GoF의 디자인 패턴을 읽으면서 정리하는 글입니다.
팩토리 메서드는?
팩토리 메서드가 중요한 패턴 중 하나라고 생각했다. 팩토리 메서드는 상위 클래스가 객체를 생성해야 하는 시점은 알고 있지만, 어떤 구체 클래스를 생성해야 하는지는 알 수 없을 때 그 결정을 하위 클래스에 맡긴다. 이를 통해 상위 클래스가 특정 구체 클래스에 직접 의존하지 않도록 한다.
그것이 해결하려는 문제는?
결론부터 말하면, 어떤 객체가 필요한지는 상위 클래스가 알고 있지만 구체적으로 어떤 하위 클래스의 객체를 만들어야 하는지 알 수 없어서 팩토리 메서드가 필요해진다.
그렇다고 상위 클래스가 특정 구체 클래스를 직접 생성하도록 하면, 상위 클래스가 그 구현에 의존하게 된다. 그러면 새로운 구체 클래스가 추가되거나 생성 대상이 바뀔 때 상위 클래스의 코드까지 수정해야 해서 확장성이 떨어진다. 이러한 의존성을 줄이려는 것이 목적이다.
팩토리 메서드의 접근은 타당할까?
팩토리 메서드에는 여러 분명한 장단점과 트레이드오프가 존재한다.
상위 클래스가 구체 클래스에 직접 의존하지 않아도 되고, 새로운 종류의 구체 객체를 생성해야 할 때 기존 상위 클래스 수정이 아닌 하위 클래스에서 생성 방식을 정의할 수 있다.
그러나 단순히 특정 객체 하나를 만들기 위해서 Creator를 상속한 하위 클래스를 만들어야 한다. 즉 클래스 수가 늘어나고 상속 구조가 복잡해진다.
장점만 본다면 확실히 매력적인 구조다. 결합도를 낮추며 책임 분리가 확실해진다. 그러나 만약 만들려는 것이 간단한 것이라면? 생성 책임 분리를 위해 상속까지 쓰는 것이 과하며 오버엔지니어링이 아닐까 생각도 든다.
확장 가능성이 실제로 높거나, 생성할 객체의 종류가 여러 구현으로 바뀔 가능성이 있을 때는 팩토리 메서드가 유용하다고 생각한다. 반대로 생성 대상이 단순하고 변경 가능성이 낮다면, 미래의 확장 가능성만을 이유로 상속 구조를 미리 만드는 것은 과한 설계가 될 것이다.
이게 싫어서 다른 대안을 적용한다면 아직은 알고 있는 패턴이 많지 않아 잘 모르겠다. 다만 앞서 공부한 빌더와 추상 팩토리는 팩토리 메서드가 해결하려는 문제를 그대로 해결하지는 못할 것이다.
빌더나 추상 팩토리도 객체 생성에 대한 결합도를 낮춘다는 점은 비슷하지만, 해결하려는 문제가 팩토리 메서드와는 다르다. 빌더는 복잡한 객체의 생성 과정을 분리하는 데 초점을 두고, 추상 팩토리는 관련된 여러 제품을 하나의 제품군으로 만드는 데 초점을 둔다. 반대로 팩토리 메서드는 어떤 구체 객체를 만들지 상위 클래스가 결정할 수 없을 때 그 결정을 하위 클래스에 맡기는 데 초점이 있다.
현재까지 읽은 범위에서는 팩토리 메서드를 직접 대체하는 다른 패턴을 찾기보다는, 상속이 필요한 상황인지 따져보는 것이 더 중요하다고 생각한다. 결국 어떤 방식을 선택할지는 생성할 객체가 단순한지, 객체의 종류가 얼마나 자주 바뀌는지, 기존 설계가 상속을 중심으로 구성되어 있는지에 따라 달라질 것 같다.
정리하자면, 팩토리 메서드가 해결하려는 문제는 타당하다. 하지만 생성 대상이 단순하거나 변경 가능성이 낮다면 상속 구조까지 만드는 건 과하다.
반례
반례를 팩토리 메서드를 쓰면 오히려 부자연스러운 상황이라고 보면, 위에서 언급한 생성할 객체가 단순하고 거의 안 바뀌는 경우이다.
앱이 항상 같은 종류의 객체만 만들고 있는데, 이걸 굳이 팩토리 메서드로 바꾸면 객체 하나 만들려고 클래스가 하나 더 생긴다. 생성하는 객체가 다른 종류로 바뀔 가능성도 없다면 얻는 유연성보다 구조 복잡도가 더 커진다.
또 다른 반례는 상속 없이 더 간단하게 해결할 수 있는 경우다. 팩토리 메서드에 대한 내 의문은 과연 상속을 통한 생성 책임 분리가 지금도 항상 필요한가이다.
내가 주로 사용하는 리액트에서는 클래스 상속보다는 함수형 컴포넌트와 함수 전달을 많이 쓴다. 생성할 함수를 외부에서 전달받도록 하면, 객체를 사용하는 쪽은 구체 클래스에 직접 의존하지 않으면서 별도의 하위 클래스를 만들 필요가 없다.
즉, 생성할 객체가 단순하고, 종류가 거의 변하지 않으며, 생성 함수를 외부에서 주입하는 것만으로도 충분한 환경에서는 팩토리 메서드를 위해 별도의 상속 계층을 만드는 것이 오히려 불필요한 복잡성을 만든다.