ComputerProgrammingwithGNUSmalltalk:5.4

From 흡혈양파의 번역工房
Jump to navigation Jump to search

나만의 클래스 만들기

GNU 스몰토크는 내장된 클래스만 수백개이지만, 온 세상은 셀 수 없을 정도로 많은 클래스를 가지고 있기 때문에, GNU 스몰토크에서는 여러분이 필요한 클래스를 만들 수 있습니다. 우리가 만든 클래스를 때로는 사용자 정의 클래스custom classes라고 부르겠습니다.


먼저, 클래스는 어떤 것들으로 만들어져 있는지 다뤄보겠습니다. 클래스들은 객체의 청사진과 같습니다. 따라서 객체가 가지는 모든 것을 명확하게 서술해야 합니다. 예를 들어, 클래스는 객체의 속성을 정의하기 위한 인스턴스 변수를 가지고 있습니다. 클래스는 어떤 특정 메시지에 대해 객체가 응답할 수 있도록 메서드 정의를 가지고 있습니다. 클래스는 위의 설명이 다가 아닙니다. 클래스 변수class variable 라는 것이 있습니다. 클래스 변수는 클래스의 상태에 대한 정보를 담고 있습니다. 또한 클래스만 실행 가능한 클래스 메서드도 있습니다. 클래스 메서드class method는 클래스만 실행시킬 수 있지, 인스턴스에서는 실행시킬 수는 없습니다.


클래스 생성을 위한 문법은 다음과 같습니다.

SuperclassName subclass: SubclassName [
  | instanceVariable1 instanceVariable2 |

  classVariable1 := anObject.
  classVariable2 := anotherObject.

  <comment: 'Comment to describe our class'>

  SubclassName class >> aClassMethod: aParameter [
    "Comment to describe this class method"
    <category: 'Category of this class method'>

    | localVariable1 localVariable2 |

    ...

    ^objectToReturn
  ]

  anInstanceMethod [
    "Comment to describe this instance method"
    <category: 'Category of this instance method'>

    | localVariable1 localVariable2 |

    ...

    ^objectToReturn
  ]
]


위의 가상 코드는 클래스를 어떻게 만들고, 클래스와 인스턴스 변수들을 어떻게 추가하고, 클래스와 인스턴스 메서드를 어떻게 추가하는지 보여주고 있습니다. 소스코드를 한 줄씩 설명하기 전에 몇몇 일반적인 개념에 대해 말하겠습니다. 위 소스코드의 대부분은 부가적인 것입니다. 예를 들어 클래스 변수나 메서드를 꼭 가지고 있을 필요는 없습니다. 혹은 주석을 달아둘 필요도 없으며, 메서드의 분류를 정의할 필요도 없습니다. 그러나 이것들은 소프트웨어 엔지니어링의 좋은 습관입니다. 그리고 항상 주석을 남기고, 메서드의 분류를 정의하기를 권장합니다.


또한 위의 코드에서 관심있는 부분은 공백의 사용입니다. 몇몇 행은 탭이나 빈칸으로 들여쓰기indent가 되어있지만, 왜 그렇게 되어 있겠습니까? 이는 인간의 눈으로 코드를 매끄럽게 보기 위한 것입니다. 또한 공백을 어떻게 사용할지에 대한 규칙은 없습니다. 대부분 어떤 새로운 구조의 본문을 들여쓰기합니다. 예를 들어, 클래스의 본문을 작성할 때, 다른 내용과 비교하여 한 단계 안으로 들여쓰기 합니다. 여기서 한 단계는 프로그래머마다 다릅니다. 들여쓰기 하는 데에 여러개의 빈 칸을 선택하거나 탭을 넣을 수도 있지만, 중요한 점은 프로그램을 통틀어 일관성을 갖는 것이 혼란스럽게 보이지 않습니다.


들여쓰기 외에도, 사용하는 대부분의 공백들이 프로그래머마다 다릅니다. 여러 단어마다 앞뒤로 빈칸을 두거나 두지 않는 것을 선택할 수 있습니다. 만약 잘못 사용하면(모호함을 초래할 때) 인터프리터는 여러분에게 오류를 전달할 것입니다. 예를 들어, 여러분은 변수 이름과 키워드 선택자를 연결하여 쓸 수 없습니다. 왜냐하면 인터프리터는 변수명이 어디에서 끝나는지, 키워드 선택자가 어디에서 시작하는지 알 수 없기 때문입니다. 따라서 적어도 빈 칸 하나를 두어야만 합니다.


위의 코드를 한 줄씩 보도록 하겠습니다. 먼저 한 일은 아래의 코드 내용으로 클래스를 정의하는 것입니다.

SuperclassName subclass: SubclassName [
  ...
]


코드에서 세 개의 점은 거기에 더 많은 수식 표현이 있다는 것을 의미합니다 (앞으로 늘 이렇게 표시하겠습니다). 진짜로 중요한 부분을 강조하기 위해 짧게 줄인 것입니다. 실제 코드에 점 세개를 두면 안됩니다. 위의 부분에서 SuperclassName 클래스에게 SubclassName 이라는 하위 클래스를 만들도록 지시한 것입니다. 상위클래스의 속성과 동작을 상속하기 위해 지정한 것이기 때문에 클래스를 다시 만들지 않아도 됩니다. 그런 다음, 클래스 변수, 인스턴스 변수, 클래스 메서드, 인스턴스 메서드를 지정하기 위해 대괄호를 열었습니다.


위의 대괄호가 열린 부분을 클래스의 헤더header라고 부릅니다. 대괄호 사이의 부분을 클래스의 본문body이라고 부릅니다.


파이프 사이에 들어있는 이름들은 클래스의 인스턴스 변수들입니다.

  | instanceVariable1 instanceVariable2 |


인스턴스 변수 이름들은 공백으로 구분합니다. 두 인스턴스 변수는 instanceVariable1과 instanceVariable2로 이름붙였습니다.


이제 지정 연산자를 사용하여 클래스 변수를 정의하겠습니다.

  classVariable1 := anObject.
  classVariable2 := anotherObject.


= 메시지는 전달받는 객체를, 인자 객체를 참조하는 객체로 만들어주는 역할을 합니다. 따라서 이제부터 classVariable1을 사용할 때, 인터프리터는 실제로 anObject 객체를 참조한다는 것으로 이해할 것입니다. 인스턴스 변수를 변경하는 것에 대해서도 앞으로 이 지정 연산자 메시지를 사용할 것입니다.


처음 변수에 관하여 언급하는 것을 변수 선언이라고 말합니다. 변수를 사용하기 전에 먼저 선언해야만 합니다.


다음 표현은 클래스에 주석을 추가합니다.

  <comment: 'Comment to describe our class'>

주석은 문서 목적으로만 쓰이며, 사용하는 IDE에서는 클래스나 메서드가 어떤 일을 하는지 설명하기 위해서 나타납니다. 따라서 시간을 들여 힘들게 코드를 보지 않고도 코드가 무엇을 하는지 생각을 얻을 수 있습니다. 주석은 프로그램 실행에 영향을 미치지 않기 때문에, 생략할 수 있습니다.


클래스와 인스턴스 메서드를 정의할 시간입니다. 먼저 클래스 메서드를 만들겠습니다.

  SubclassName class >> aClassMethod: aParameter [
    "Comment to describe this class method"
    <category: 'Category-of-this-class-method'>

    | localVariable1 localVariable2 |

    ...

    ^objectToReturn
  ]


여기 헤더부분과 본문부분이 있습니다. 클래스 선언의 헤더는 다음과 같습니다.

  SubclassName class >> aClassMethod: aParameter


이 헤더의 SubclassName class >> 부분은 클래스의 인스턴스가 아닌, 클래스에 대한 메서드를 생성할 것을 알려주고 있습니다. 만약 이 부분을 생략하면 메서드는 이 클래스의 인스턴스의 것이 됩니다. 이후 이 부분을 메서드의 메시지라고 합니다. 이 메시지의 선택자는 aClassMethod:입니다. 파라미터는 aParameter라고 이름붙였습니다. 파라미터parameter들은 메서드의 헤더에서 사용할 때 인자이름으로 주어진 이름입니다. 따라서 이 단어는 실제로 인자와 다를바 없습니다. 그리고 때때로 교환해서 사용합니다. 메서드 안의 파라미터 이름을, 메서드에 전달하기 위한 인자를 참조하는 방법으로 사용합니다.


선택자를지정한 후에 메서드의 본문이라 불리는 메서드 내용을 정의하기 위해 대괄호를 열었습니다.

  [
    "Comment to describe this class method"
    <category: 'Category of this class method'>

    | localVariable1 localVariable2 |

    ...

    ^objectToReturn
  ]


메서드의 내용은 주석, 범위, 몇몇의 지역 변수와, 점 세개로 표시한 실행할 표현식으로 구성할 수 있습니다. 주석을 쓴 후에

    "Comment to describe this class method"


다음과 같이 이 메서드의 분류를 지정할 수 있습니다.

    <category: 'Category of this class method'>


이것은 부가적인 것입니다. 따라서 우리는 주석을 쓰거나 메서드에 대한 분류를 지정할 필요는 없습니다.


메서드의 본문은 중요한 부분입니다. 먼저 지역 변수를 선언합니다.

    | localVariable1 localVariable2 |


이는 인스턴스 변수를 선언하는 것과 같습니다. 지역 변수는 메서드에 한하여 지역적이며, 메서드 본문 바깥에서는 사용할 수 없습니다.


다음으로 객체 이름 앞에 ^ 문자를 붙여서 호출자에게 되돌려줄 변수로 objectToReturn 객체를 반환합니다.

    ^objectToReturn


이 부분은 반환 표현이며, 메시지가 실행된 결과 값이기도 합니다. 예를 들어, 2 + 3 을 수행할 때, 그러한 표현을 통해 5라는 값을 반환할 것입니다. 반환 표현을 사용하여 값을 반환하는 것 또한, 두가지 이유에서 부가적인 것입니다. 첫번째로, 모든 메서드가 응답 객체를 필요로 하는 것은 아닙니다. 마치 표준 출력에 몇몇 문자를 표시하는 것과 같습니다. 두번째로 메서드는 여러분이 반환 기호를 표시하지 않으면, 마지막 수식표현을 반환합니다. 그러나 반환함을 정확하게 명시하는 것은 좋은 프로그래밍 습관이므로, 소스코드를 읽는 사람들이 명확하게 알 수 있도록 반환값을 표현해주는 것이 좋습니다.


마지막으로 말할 것은 인스턴스 메서드입니다.

  anInstanceMethod [
    "Comment to describe this instance method"
    <category: 'Category of this instance method'>

    | localVariable1 localVariable2 |

    ...

    ^objectToReturn
  ]


이 코드 부분에 대해선 자세히 이야기하지 않겠습니다. 왜냐하면 인스턴스 메서드를 만드는 헤더부분에 클래스 이름이 없다는 것을 제외하고는 거의 클래스 메서드와 흡사하기 때문입니다. 따라서 이 메서드는 모든 인스턴스에 공통적으로 존재하게 될 것입니다.


Notes