[HeadFirst Design Pattern] Factory Pattern - client code의 이해

JUHYUN·2024년 9월 28일
0

🌌 Problem : new

  • new 를 쓴다는 것은 구체적인 클래스를 사용해 인스턴스를 만들기 때문에 변경에 취약한 코드가 됩니다.
  • 한 타입에 여러가지 구체 클래스가 있다면, 알맞은 인스턴스 생성을 위해 복잡한 if문을 사용해야 할 수도 있습니다.
  • 하지만 단순히 if 문을 사용한다고 해서 문제가 되지 않습니다.
  • 문제인지 아닌지는 new 를 사용해 concrete instantiation을 사용한 곳이 client code 가 될 수 있는지에 대한 여부입니다.
    ** concrete instantiation: 구체 클래스를 사용한 인스턴스 생성 (new 키워드 사용)

💫 What is Client Code?

헤드퍼스트 디자인패턴 책에서는 다음과 같은 말이 나옵니다.

Don't forget, we are also just about to remove the concrete instantiations from our client code!
(p.115)

그럼 여기서 client code 는 뭘까요?
바로 전 페이지에서 관련된 말이 있습니다.

Once we have a SimplePizzaFactory, our orderPizza() method just becomes a client of that object
(p.114)

즉, A 클래스에서 B 클래스의 메서드를 호출한다면 A 클래스는 B 클래스의 client 인 것이라고 이해할 수 있었습니다.

💫 Client Code, 너무 상대적인 거 아니야?

이 다음 제가 들었던 의문입니다. 위와 같은 이해를 했을 때 Client Code는 2개 이상의 클래스 관계에서 나올 수 있는 표현이라고 생각하기 때문입니다. 따라서

Don't forget, we are also just about to remove the concrete instantiations from our client code!
(p.115)

위의 표현은 제게 굉장히 어색한 표현으로 느껴졌습니다.
따라서 저는 복잡한 if 문의 Pizza 생성 로직을 SimplePizzaFactory 로 옮김에 따른 효과에 집중해서 client Code를 이해해보기로 하였습니다. 결국 제가 어색하게 느껴진 표현이더라도 글쓴이는 궁극적으로 이 Action에 대한 효과를 이야기하고 싶었을 것이기 때문입니다.

💫 그 효과는?

기존 코드

Pizza orderPizza(String type) {
	Pizza pizza;
    
    if (type.equals("cheese")) {
    	pizza = new CheesePizza();
    } else if (type.equals("greek") {
		pizza = new GreekPizza();
    } else if (type.equals("pepperoni") {
    	pizza = new PepperoniPizza();
    }
    
    pizza.prepare();
    pizza.bake();
    pizza.cut();
    pizza.box();
    return pizza;
}

개선 코드

public class PizzaStore {
	SimplePizzaFactory factory;
    
    public PizzaStore(SimplePizzaFactory factory) {
    	this.factory = factory;
    }
    
    public Pizza orderPizza(String type) {
    	Pizza pizza;
        
        pizza = factory.createPizza(type); // 기존 코드의 if문을 사용한 인스턴스 생성 로직 포함
        
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

✨ 효과

  • 서비스에서 변경이 일어나기 쉬운 부분과 그렇지 않은 부분이 분리되었습니다.
    • 변경이 일어나기 쉬운 부분 : 종류별 Pizza 생성
  • 기존에 2가지 책임을 가지고 있었던 orderPizza 메서드가 한 가지 책임만을 갖게 되었습니다.
  • createPizza 메서드화를 통해 Pizza 생성 로직에 대한 중복된 코드를 줄일 수 있습니다.
  • Pizza 종류에 변경이 생긴다고 하더라도 createPizza 한 곳에서만 변경이 일어납니다.

💫 효과를 고려한 Client Code 재이해

사실 코드를 봤을 때 의존관계를 확인한다면 누가 누구의 Client Code 인지는 금방 나올 것이라 생각합니다. 따라서 조금 더 좁혀서

remove the concrete instantiations 을 할만한 client code 가 될 수 있는가?

에 초점을 맞추어보았습니다. 위의 기존코드만 보았을 때, "아, 이 코드는 어떤 PizzaFactory의 client code 가 될 수 있겠네." 라는 생각이 들게끔 말이죠.

저는 위의 효과를 토대로 이 기준을 아래와 같은 두 가지로 정의해볼 수 있었습니다.

  1. 변경의 빈도가 서로 다른 코드가 함께 있는가?
  2. 한 메서드가 2가지 이상의 책임을 가지고 있는가?

여기에 모두 yes 라고 답할 수 있다면, new 키워드를 사용한 인스턴스화 부분을 새로운 클래스로 분리하여 기존 코드를 새로운 클래스의 client code로 만들 수 있을 것입니다.


** 후기

영어로 책을 보는게 쉽지 않은 것 같네요. 간혹 이렇게 이해가 되지 않는 표현을 그냥 넘어가면(특히 핵심이 있는 곳에서) 이후의 내용이 잘 안들어오더라구요ㅠㅠ 어차피 책 뿐만 아니라 개발하며 검색하는 자료도 영어인 경우가 많아 정리하기로 마음먹고 정리하기로 했는데 생각보다 본 글에 대한 이해도가 더 높아진 것 같습니다😄

profile
행복과 같은 속도를 찾는 개발자

0개의 댓글