ABOUT ME

이 곳에 찾아와주신 모든 분들께 제 문서가 도움이 되길 진심으로 바랍니다.

Today
Yesterday
Total
  • [수정중] 헤드퍼스트 디자인 패턴 [4]
    Development/디자인 패턴 2018. 1. 2. 01:05

    헤드퍼스트 디자인 패턴[4]


    1. 팩토리 패턴


    preface: new 키워드에 대하여..


    new 구상객체를 뜻한다. 구상 클래스의 인스턴스를 만드는 .

    인터페이스를 써서 코드를 유연하게 만들 있다 하더라도 인스턴스를 만드는건 피할 없다. 인스턴스 형식은 실행시의 조건에 따라 결정된다. 수정할 이런 코드르 보고 추가/제거 해야된다는 -> 관리가 힘듦 -> 오류가 많이 터짐.


    근데 new 안쓰면 객체를 못만든다. 고로 new 특성중 조심해야하는 것이 있다는 말이 된다.

    따라서 '확장에 대해서는 열려있되, 변화에 대해서는 닫혀있는 코드(OCP based code)' 짜야한다 이말. => 추상화!




    바뀌는 부분을 찾아서 캡슐화하면 될것이다!


    너는 이제 피자가게를 운영하고있다고 치자. 피자 주문을 받으면 만드는걸로 하자.

    150, 151쪽의 소스를 보면 변화가 쉬운 코드다! -> 불건전하다. 캡슐화 필요.

    캡슐화하는 객체의 이름은 Factory()라고 하자.


    simpleFactory 라는 클래스를 만들고 분리해도 일단 간단한 패턴형태로 처리할 있다.


    -----


    일단 처리됨. 근데 다음에 피자가게가 워낙에 잘돼서 프랜차이즈를 만들었다 치자. 근데 이제 지역별로 다른 스타일의 피자를 만들고 싶다면?


    그래서 피자가게 프레임워크로 판을 키움.


    -> abstract class안에 피자 주문을 따로만듦.

    -> 피자만드는 메소드도 abstract class 만듦.


    다시말해, 피자 만드는 방법에 대해 추상화. '어디 스타일의 피자를 만든다' 하는 행동을 만들어놓고 구현은 실제 자식이 하도록.. 

    추상메소드로 해놨기 때문에 new 안씀. 다른방법으로 구현을 위임한다.


    추상화를 통해 소스코드들이 분리되어있음. 이제 팩토리 메소드 선언!


    protected abstract Pizza createPizza(String type); //피자 인스턴스를 만드는건 임마가 알아서 맡고 처리함.

    팩토리 메소드를 이용하면 객체를 생성하는 작업을 서브클래스에 캡슐화시킬 있다. 이러면 슈퍼클래스에 있는 클라이언크 코드와 서브클래스에 있는 객체 생성 코드를 분리할 있음.

    -> abstract Product factoryMethod(String type)

    • 추상메소드로 선언: 서브클래스에서 객체생성을 책임지게
    • 팩토리 메소드에서는 특정 제품(객체) 리턴하며, 객체는 보통 슈퍼클래스에서 정의한 메소드 내에서 쓰인다.
    • 팩토리 메소드는 클라이언트에서 실제로 생성되는 구상 객체가 무엇인지 없게 한다.
    • 매개변수를 통해 만들어낼 객체종류를 선택할 수도 있다.


    PizzaStore... 서브클래스에서 피자가 만들어지기 위해 구현할 팩토리 메소드를 정의함.

    Pizza... 팩토리에서는 제품을 생산한다. 다시말해 만드는 제품을 구현(초기화)하는데 집중한다. 


    둘다 추상클래스로 시작하고, 클래스를 확장함.

    구체적인 구현은 구상 클래스들이 수행한다.

    NYPizzaStore에는 뉴욕풍 피자를 만드는 지식이 캡슐화되어있음.

    ChicagoPizzaStore에는 시카고풍 피자를 만드는 지식이 캡슐화되어있음.


    이것이 바로 팩토리 메소드 패턴!


    팩토리 메소드 패턴: 객체를 생성하기 위한 인터페이스를 정의. 어떤클래스의 인스턴스를 만들지는 서브클래스에서 결정하게 한다. 다시말해 클래스의 인스턴스를 만드는 일을 서브클래스에 위임한다.


    만약 객체 인스턴스를 직접 만들게 되면 부모 클래스가 자식 클래스에 의존하게 된다! 피자가게에서 뉴욕스타일의 /// 피자, 시카고스타일의 /// 피자 모두를 만들게된다 이말. 추가/삭제하기 상당히 골치아픈 모양새가 .


    구상 클래스에 대한 의존성을 줄이는것이 좋다! 이것이 바로 의존성 뒤집기 원칙!


    --------------------------------------------------------------------------------------

    | 디자인 원칙 - 6 : 추상화된 것에 의존하도록 만들어라. 구상 클래스에 의존하도록 만들지 않도록 한다. |

     -------------------------------------------------------------------------------------


    추상화를 해서 고수준의 구성요소가 저수준의 구성요소에 의존하게 만들면 안된다!

    예를들어 pizzastore 행동은 피자에의해 정의된다. pizzastore 고수준 구성요소다.

    pizzastore내에서 피자를 준비하고 굽고 자르고 포장하는건 피자객체인데 이건 저수준 구성요소다.


    이걸 하는방법!

    pizzastore 구현하고싶다! 제일먼저 해야할까?

    -> 피자를 준비하고 굽고 포장해야한다.

    -> 치즈피자, 야채피자, 조개피자 등의 메뉴를 갖춰야된다.


    피자가게에서 구상피자형식을 직접 알고있게하면 안된다! 여기서 해야할까?

    -> 저수준의 중에 추상화할 있는 것을 생각하라!

    -> 치즈피자건, 야채피자건 모두 피자다!


    추상화는 했는데 구상 클래스는 어떻게 없애야할까?

    -> 팩토리를 사용하면 구상피자 형식이 추상화된 피자에 의존하게됨!

    -> 이러면 의존성이 뒤집힘!


    다음 가이드라인을 따라서 디자인하면 도움이 된다!

    • 어떤 변수에도 구상클래스에 대한 레퍼런스를 저장하지 말자.
      (new
      남발하면 안된다는 . 팩토리를 써서 구상 클래스에 대한 레퍼런스를 변수에 저장하는 일을 없애야한다)
    • 구상 클래스에서 유도된 클래스를 만들지 말자.
      (
      특정 구상클래스에 의존하게되지 않도록.. 추상화된 것으로부터 클래스를 만들어야함. 가령 추상클래스)
    • 베이스 클래스에 이미 구현되어있던 메소드를 오버라이드하지 말자.
      (
      구현된 메소드를 오버라이드 하는건 추상화가 덜되었다는 . 베이스 클래스에서는 모든 서브클래스에서 공유할 있는 것들만 정의해야함)


    ---


    원재료에 대한 품질관리도 필요함! 일종의 원재료군(families of ingredients) 처리해야한다.


    모든 피자는 같은 구성요소로 이루어지지만, 지역마다 구성요소를 다르게 구현한다.

    • 가령 뉴욕의 해산물 토핑, 시카고의 해산물 토핑이 다를 밖에 없는 이유...


    원재료 팩토리를 만들자.


    지역별로 팩토리를 만듦. 생성 메소드를 구현하는 PizzaIngredientFactory 클래스를 만듦.

    ReggianoCheese, RedPeppers, ThickCrustDough같은 팩토리에서 쓰일 원재료 클래스를 구현함. (다양하게 쓰일 있음)

    새로만든 원재료 공장을 PizzaStore에서 있게 만들어줌.


    이제 피자가게에서는 사용할 팩토리만 넣어주면 . 그러면 제품군까지 고려할 있는 패턴이 된다.


    이것이 바로 추상 팩토리 패턴!


    추상 팩토리 패턴: 인터페이스를 이용하여 서로 연관된, 또는 의존하는 객체를 구상 클래스를 지정하지 않고도 생성할 있다.

Designed by Tistory.