SmalltalkBestPracticePatterns:8.4

From 흡혈양파의 번역工房
Jump to: navigation, search
8.4 Arithmetic (산술)

Arithmetic (산술)

두 개의 Money를 어떻게 합칠까? 간단한 case, 즉 두 개의 Money에 동일한 통화를 가지는 경우를 먼저 올바르게 만들어보자. 동일한 통화로 된 두 개의 Money를 추가할 때는 결과적 Money는 첫 번째 두 개를 합한 금액만큼 가져야 한다.

Money>>+ aMoney
    ^self species
        amount: amount + aMoney amount
        currency: currency


이것이 작동하려면 "amount" 변수에 Getting Method가 필요하다:

Money>>amount
    ^amount


달러에 달러를 추가하고 있다면 올바른 해답을 얻는다:

| m1 m2 |
m1 := Money
    amount: 5
    currency: #USD.
m2 := Money
    amount: 7
    currency: #USD.
m1 + m2 12 USD


Moneys를 다른 통화로 변경할 경우 틀린 해답을 얻는다:

| m1 m2 |
m1 := Money
    amount: 5
    currency: #USD.
m2 := Money
    amount: 7
    currency: #GBP.
m1 + m2 12 USD


5 달러와 7 파운드를 합하면 12 달러가 아니다. 산술에 간단한 "+" 프로토콜을 유지하면서 다수의 통화를 가진 case를 처리할 수 있는 방법으로 무엇이 있을까? 해답은 Money에 대해 Imposter를 (모델링 패턴) 도입하여 환율 변환을 따르는 것이다. 그것으로 MoneySum라는 Simple Superclass Name(간단한 슈퍼클래스명)을 제공한다.

Class: MoneySum
    superclass: Object
    instance variables: monies


Role Suggesting Instance Variable Name(역할을 제안하는 인스턴스 변수) "monies"를 이용한 변수는 Moneys의 Collection을 보유할 것이다. Constructor Method(생성자 메서드)를 이용해 MoneySum을 생성한다:

MoneySum class>>monies: aCollection
    ^self new setMonies: aCollection


컬렉션은 Constructor Parameter Method(생성자 파라미터 메서드)로 옮겨간다:

MoneySum>>setMonies: aCollection
    monies := aCollection


Debug Print Method(디버그 인쇄 메서드)를 MoneySum으로 추가하면 결과를 확인할 수 있다:

MoneySum>>printOn: aStream
    monies do:
        [:each |
        aStream
            print: each;
            nextPutAll: ' + '].
    aStream skip: -3


이 메서드에서는 꽤 많은 패턴들이 사용되었다: Direct Variable Access(직접 변수 접근), Role Suggesting Parameter Name(역할을 제안하는 파라미터명), Simple Enumeration Parameter(간단한 열거 파라미터), Rectangular Block(직사각형 블록), Indented Control Flow(들여쓴 제어 흐름), Do. MoneySum을 사용할 수 있다면 두 개의 통화가 일치하지 않을 시 MoneySum을 리턴하도록 Money>>+를 수정할 수 있다.

Money>>+ aMoney
    ^currency = aMoney currency
        ifTrue:
            [self species
                amount: amount + aMoney amount
                currency: currency]
        ifFalse:
            [MoneySum monies: (Array
                with: self
                with: aMoney)]


Money의 통화에 Getting Method가 필요하다:

Money>>currency
    ^currency


이제 우리의 복수통화 예제가 작동한다:

| m1 m2 |
m1 := Money
    amount: 5
    currency: #USD.
m2 := Money
    amount: 7
    currency: #GBP.
m1 + m2 5 USD + 7 GBP


확인차 단일통화 예제를 시도해보니 작동한다:

| m1 m2 |
m1 := Money
    amount: 5
    currency: #USD.
m2 := Money
    amount: 7
    currency: #USD.
m1 + m2 12 USD


Notes