Eternity's Chit-Chat

aeternum.egloos.com



유연한 설계를 위한 패턴과 원리 - 3.리팩토링을 통한 진보 7부 Supple Design

 Ratio 분모와 분자를 속성으로 가지고 분자를 분모로 나눈 비율을 계산할 책임을 진다. 계산 적용할 소수점 이하 자릿수와 반올림 여부를 지정할 있어야 한다. 예를 들어 20:3 계산 소수점 이하 2자리까지 계산하고 반올림한다면 결과로 6.667 얻을 것이다. 테스트를 작성하자.

 

RatioTest.java

@Test

public void applyScale3_and_HALF_EVENE() {

  Ratio ratio = Ratio.of(20, 3);

  assertEquals(new BigDecimal(6.667).setScale(3, RoundingMode.HALF_EVEN.ordinal()),

    ratio.toDecimal(3, RoundingMode.HALF_EVEN));

}

 

Ratio.of() CREATION METHOD 추가하고 지정한 소수점 이하 자리와 반올림 모드를 사용하여 비율을 계산하는 toDecimal() 메소드를 작성한다. 테스트를 통과하는지 확인하자. 

 

Ratio.java

public class Ratio {

  private BigDecimal numerator;

  private BigDecimal denominator;

 

  public static Ratio of(int numerator, int denominator) {

    return new Ratio(new BigDecimal(numerator), new BigDecimal(denominator));

  }

 

  public static Ratio of(BigDecimal numerator, BigDecimal denominator) {

    return new Ratio(numerator, denominator);

  }

 

  Ratio(BigDecimal numerator, BigDecimal denominator) {

    this.numerator = numerator;

    this.denominator = denominator;

  }

 

  public BigDecimal toDecimal(int scale, RoundingMode rounding) {

    return numerator.divide(denominator, scale, rounding.ordinal());

  }

}

 

double 타입을 사용해서 비율을 지정할 있다면 사용하기가 용이할 같다. 비율의 분모에는 소수점을 무시한 전체 수를, 분자 값은 소수점 이하 자릿수를 10 지수로 결과값을 저장하기로 하자. , 비율이 1270.52 경우 분모에는 127052, 분자에는 100 대입하는 것이다. 비율의 분모와 분자에 정확한 값이 저장되는 지를 확인하기 위해 Ratio.getNumerator() Ratio.getDenominator() 메소드를 추가하기로 결정했다.

 

RatioTest.java

@Test

public void doubleRatio() {

  Ratio ratio = Ratio.of(1270.52);

  assertEquals(new BigDecimal(127052), ratio.getNumerator());

  assertEquals(new BigDecimal(100), ratio.getDenominator());

}

 

double 타입을 분모와 분자로 변환하기 위해 전달된 비율을 문자열로 변환하여 소수점 이하 자릿수의 길이를 구한 분모에는 소수점을 무시한 전체 값을, 분자에는 소수점 이하 자릿수의 길이를 지수로 하고 10 밑수로 계산한 결과를 대입한다.

 

Ratio.java

public static Ratio of(double ratio) {

  String ratioString = new Double(ratio).toString();

  int scale = ratioString.length() – ratioString.lastIndexOf(".") - 1;

  BigDecimal coversionRatio =

    new BigDecimal(ratio).setScale(scale, RoundingMode.HALF_EVEN.ordinal());

 

  return of(new BigDecimal(coversionRatio.unscaledValue()),

    new BigDecimal(Math.pow(10, scale)));

}

 

환전 금액을 계산하기 위해서는 환전하고자 하는 액수에 환율을 곱해야 한다. Ratio Money 매개변수로 취하는 times() 메소드를 추가하면 환율 계산이 쉬워질 같다. 하지만 Ratio Money 매개변수로 취할 경우 오직 금액 간의 비율을 표현하는 데에만 사용될 있다. Ratio 범용적인 클래스로 만들기 위해서는 Money 대한 의존성을 추가하는 보다는 표준 라이브러리의 BigDecimal 매개변수로 받도록 하는 것이 유용할 것이다. Money 대신 BigDecimal 대한 의존성을 가지도록 함으로써 Ratio STANDALONE CLASS 만들 있다.

 

RatioTest.java

@Test

public void timesByBigDecimal() {

  assertEquals(
   
new BigDecimal(13.333).setScale(3, RoundingMode.HALF_EVEN.ordinal()),

    Ratio.of(20, 3).times(BigDecimal.valueOf(2))
     
.toDecimal(3, RoundingMode.HALF_EVEN));

}

 

times() 구현은 간단하게 분모에 넘겨진 BigDecimal 매개변수를 곱하면 된다. Ratio 역시 VALUE OBJECT이므로 새로운 인스턴스를 생성하여 반환한다.

 

Ratio.java

public Ratio times(BigDecimal multiplicand) {

  return Ratio.of(numerator.multiply(multiplicand), denominator);

}

 

마지막으로 남은 것은 비율의 역수를 구하는 것이다.

 

RatioTest.java

@Test

public void inverse() {

  assertEquals(Ratio.of(3, 20), Ratio.of(20, 3).inverse());

}


덧글

  • 병훈 2010/03/19 11:33 # 삭제

    과장님 글 잼께 보고 있어요 ^^
    방명록은 어디있나요??
  • 이터너티 2010/03/19 15:34 #

    병훈 과장님 방문 감사합니다.
    이글루스는 방명록 어떻게 만들더라...
    함 만들어 볼께요. ^^;;
※ 로그인 사용자만 덧글을 남길 수 있습니다.