본문 바로가기

Java/DesignPattern

[HeadFirst] 4장 팩토리 패턴

  • new 연산자가 눈에 띈다면 '구상'이라는 용어를 떠올리자
    • new를 사용하면 구상 클래스의 인스턴스가 만들어진다
    • 인터페이스가 아닌 특정 구현을 사용하는 코드가 된다.
    • 구상 클래스를 바탕으로 코딩하면 나중에 코드를 수정해야 할 가능성이 커지고 유연성이 떨어진다.
    • 구상 클래스의 인스턴스 생성 부분을 나무지 부분으로 캡슐화 하자
Duck duck;
if(picnic){
	duck = new simpleDuck();
}else if(hunting){
	duck = new DecoyDuck();
}....
  • 객체 생성 부분 캡슐화
    • 객체 생성을 처리하는 클래스를 팩토리라고 부릅니다.
    • 객체 생성 부분을 전담할 클래스를 정의해서 사용한다.
    • 객체 생성 작업을 팩토리 클래스로 캡슐화 해놓으면 구현을 변경할 때 팩토리 클래스 하나만 고치면 된다.
    • 간단한 팩토리를 정적 메소드로 정의하는 기법인 '정적 팩토리'도 있다. 하지만 서브클래스를 만들어서 객체 생성 메소드의 행동을 변경할 수 없다.
  • 간단한 팩토리
    • 디자인 패턴이라기 보다는 프로그래밍에서 자주 쓰이는 관용구에 가깝다.
  • 디자인 패턴을 이야기 할때 "인터페이스를 구현한다"라는 표현은 자바 인터페이스를 구현하는 클래스를 만든다 라고 생각하면 안됩니다. 일반적으로 어떤 상위 형식(클래스와 인터페이스)에 있는 구상 클래스는 그 상위 형식의 '인터페이스를 구현하는' 클래스라고 생각하자
  • 팩토리 패턴예제
PizzaStore nyPizzaStore = new NYPizzaStore();

nyPizzaStore.orderPizza("cheese");

Pizza pizza = createPizza("cheese");

pizza.prepare();
pizza.cut();

//PizzaStore와 Pizza는 완전히 분리되어 있다.
//Pizza는 추상 클래스로 정의해서 orderPizza()는 실제로 어떤 구상 클래스에서 작업이 처리되고 있는지 모른다.
//여기서 PizzaStore은 생산자클래스, Pizza는 제품클래스 이다.
//이 두 클래스는 병렬로 구성되어있으며 추상 클래스로 시작합니다.
//PizzaStore은 NYPizzaStore, Pizza는 NYStyleCheesePizza등으로 구상클래스를 만들어 사용합니다.
  • 팩토리 메소드 패턴
    • 모든 팩토리 패턴은 객체 생성을 캡슐화합니다.
    • 팩토리 메소드 패턴은 서브클래스에서 어떤 클래스를 만들지 결정함으로써 객체 생성을 캡슐화합니다.
    • 객체를 생성할 때 필요한 인터페이스를 만듭니다. 어떤 클래스의 인스턴스를 만들지는 서브 클래스에서 결정합니다. 팩토리 메소드 패턴을 사용하면 클래스 인스턴스 만드는 일을 서브클래스에게 맡기게 됩니다.
    • 구상 생산자 클래스가 하나밖에 없더라도 팩토리 메소드 패턴을 사용해도 된다.
    • 팩토리 메소드와 생산자 클래스는 꼭 추상으로 정의하지 않아도 된다.
  • 객체 의존성 살펴보기
    • 객체 인스턴스를 직접 만들면 구상 클래스에 의존해야한다.
    • 예를들어 PizzaStore은 모든 피자 객체를 팩토리에 맡겨서 만들지 않고 PizzaStore 클래스 내에서 직접 만들었다.
  • 의존성 뒤집기 원칙
    • 추상화된 것에 의존하게 만들고 구상클래스에 의존하지 않게 만든다.
    • 심하게 의존적인 PizzaStore의 문제점 고치기
      • orderPizza() 메소드에서 구상 형식의 인스턴스를 직접 만들기 때문에 의존적이다.
      • orderPizza() 에서 인스턴스를 만드는 부분을 뽑아내자 > Pizza라는 추상클래스를 중간에 두자
    • 변수에 구상 클래스의 레퍼런스를 저장하지말자(new 연산자 줄이기)
    • 구상 클래스에서 유도된 클래스를 만들지 말자(인터페이스나 추상 클래스처럼 추상화된 것으로 부터 클래스를 만들자)
    • 베이스 클래스에 이미 구현되어 있는 메소드를 오버라이드 하지말자(베이스 클래스에서 메소드를 정의할 때는 모든 서브 클래스에서 공유할 수 있는 것만 정의하자)
    • Pizza 추상클래스 구현하기
      • 팩토리로 피자 재료를 만든다. 만들어지는 재료는 어떤 팩토리를 쓰는지에 따라 달라진다.
      • 피자 클래스는 어떤 재료가 배달되는지 전혀 신경쓰지 않는다.
      • 피자 클래스와 지역별 재료가 분리되어있어, 어떤 팩토리를 사용하든 클래스는 그대로 재사용 할 수 있다.
sauce = ingredientFactory.createSauce();
//sauce는 인스턴스 변수에 사용할 특정 소스의 레퍼런스를 대입
//ingredientFactory는 원재료 팩토리이다. Pizza 클래스는 원재료 팩토리가 맞기만하면 사용가능
//'추상 팩토리'라고 부르는 새로운 형식의 팩토리를 도입해서 피자 종류에 맞는 원재료군을 생산하는 방법 구축
  • 추상 팩토리 패턴
    • 구상 클래스에 의존하지 않고도 서로 연관되거나 의존적인 객체로 이루어진 제품군을 생산하는 인터페이스를 제공합니다. 구성 클래스는 서브클래스에서 만듭니다.
    • 팩토리 메소드 패턴은 클래스, 추상 팩토리 패턴은 클래스+객체를 써서 구성

'Java > DesignPattern' 카테고리의 다른 글

[HeadFirst] 5장 싱글턴 패턴  (0) 2022.08.24
[HeadFirst] 3장 데코레이션 패턴  (0) 2022.08.13
[헤드퍼스트] 2장 옵저버 패턴  (0) 2022.08.07
[헤드퍼스트] 1장 전략패턴  (0) 2022.08.02