ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 켄트 벡의 구현 패턴 - 메소드
    My-Book(History) 2016. 10. 29. 21:09

    조합 메소드


    - 켄트 벡은 전체 구조를 읽을 때는 긴 메소드를 사용하는것을 좋아한다. 하지만 세부 사항을 이해하려 할 때, 

    긴 메소드는 오히려 방해가 되므로 밀접하게 관련된 코드만 모아놓고 관련성이 떨어지는 코드는 분리하는 편이다.


    - 메소드를 구성할 때는 추측이 아닌 사실에 근거하라. ( 일단 동작하는 코드를 만들고 구성 방식을 결정하라)


    - 켄트 벡은 로직을 나누고 난 뒤 코드를 읽기 어려운 경우 모든 메소드를 인라인시켜서 커다란 메소드를 만든 후

    메소드 구현에서 새로 얻은 경험을 바탕으로 다시 메소드를 나누는 방법을 사용한다.



    의도 제시형 이름


    - 메소드의 이름을 지을 때는 그 메소드를 호출하는 입장에서 생각해서 지어라. 


    - 왜 이 메소드를 사용해야 하는가? 메소드 이름에서 이 질문에 대한 답을 얻을 수 있어야 한다.


    - 메소드 이름은 그 메소드를 호출하는 코드가 표현하려 하는 바에 도움을 줄 수 있도록 지어야 한다.


    메소드 객체


    - 복잡하게 꼬여 있는 메소드를 읽기 쉽고 명확하면서도 세부 구현 전달이 쉽도록 바꿔준다.


    - 메소드 객체를 생성할 때는 먼저 많은 수의 파라미터와 임시 변수를 사용하는 긴 메소드를 찾아보라.


    1. 메소드 이름을 따서 클래스 이름을 정한다.

    2. 메소드에서 사용하는 각 파라미터, 지역 변수, 필드에 대해 새로운 객체상의 필드를 생성한다. 일단 기존에 사용한 이름과 같은 이름을 사용한다.

    3. 본래 메소드의 파라미터와 메소드에서 사용하는 필드를 파라미터로 취하는 생성자를 만든다.

    4. 본래 메소드를 새로운 클래스의 메소드로 복사한다.

    5. 기존 메소드의 본문을 새로운 객체의 인스턴스를 생성한 후 복사한 메소드를 호출하는 코드로 바꾼다.


    <변경 전>

    1. class ComplexCalculator  
    2. {  
    3.     private final MethodObjectSample _mos;  
    4.     private int one;  
    5.     private int two;  
    6.     private int three;  
    7.     private int result1;  
    8.     private int result2;  
    9.   
    10.     ComplexCalculator (MethodObjectSample mos, int one, int two, int three)  
    11.     {  
    12.         _mos = mos;  
    13.         this.one = one;  
    14.         this.two = two;  
    15.         this.three = three;  
    16.     }  
    17.   
    18.     int calculate()  
    19.     {  
    20.         result1 = one + two + three + _mos.otherMethod();  
    21.         externalMethod();  
    22.         return result1 + result2;  
    23.     }  
    24.   
    25.     void externalMethod()  
    26.     {  
    27.         result2 = (one * two * three) + _mos.otherMethod();  
    28.     }  
    29. }  
    30.   
    31.   
    32. class MethodObjectSample  
    33. {  
    34.     int complexCalculation (int one, int two, int three)  
    35.     {  
    36.         return new ComplexCalculator(this, one, two, three).calculate();  
    37.     }  


    <변경 후>

    1. class ComplexCalculator  
    2. {  
    3.     private final MethodObjectSample _mos;  
    4.     private int one;  
    5.     private int two;  
    6.     private int three;  
    7.     private int result1;  
    8.     private int result2;  
    9.   
    10.     ComplexCalculator (MethodObjectSample mos, int one, int two, int three)  
    11.     {  
    12.         _mos = mos;  
    13.         this.one = one;  
    14.         this.two = two;  
    15.         this.three = three;  
    16.     }  
    17.   
    18.     int calculate()  
    19.     {  
    20.         result1 = one + two + three + _mos.otherMethod();  
    21.         externalMethod();  
    22.         return result1 + result2;  
    23.     }  
    24.   
    25.     void externalMethod()  
    26.     {  
    27.         result2 = (one * two * three) + _mos.otherMethod();  
    28.     }  
    29. }  
    30.   
    31.   
    32. class MethodObjectSample  
    33. {  
    34.     int complexCalculation (int one, int two, int three)  
    35.     {  
    36.         return new ComplexCalculator(this, one, two, three).calculate();  
    37.     }  


    오버라이드


    - 상위 클래스 메소드는 하위 클래스 중 같은 이름의 메소드에서만 호출하는 것이 좋다. 

    (하위클래스와 상위클래스의 여러 메소드를 자유롭게 혼합해서 사용한다면, 클래스의 흐름을 이해하기 어렵고 오류를 포함할 가능성도 높다.)


    - 메소드 오버로드는 파라미터 타입만 다를 뿐, 같은 연산을 수행해야 한다.

    - 의도가 다르다면 새로운 이름을 갖는 메소드를 사용하는 것이 좋다. 별도의 연산에 대해서는 각각 다른 이름을 사용하라.



    공장 메소드(정적 메소드)



    - 추상 타입을 반환할 수 있다는 장점이 있다.


    - 의도가 담긴 별도의 이름을 가질 수 있다.


    - 객체를 캐쉬에 저장해 놓거나, 런타임에 타입이 결정되는 하위클래스를 반환하거나 등을 하는 경우 유용하다.


    - 객체 생성 이외에 어떤 작업이 일어나는가 하는 의문을 갖게 된다.


    - 평범한 객체 생성을 하는 경우에는 생성자를 사용하라.

Designed by Tistory.