SqueakByExample:5.4

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

모든 클래스는 super클래스를 가집니다

스몰토크에서 각각의 클래스는 유일한 하나의 super클래스로부터, 클래스의 동작 그리고 구조에 대한 설명을 상속받습니다. 스몰토크는 단일 상속을 지원합니다.


SmallInteger superclass ⇒ Integer
Integer superclass ⇒ Number
Number superclass ⇒ Magnitude
Magnitude superclass ⇒ Object
Object superclass ⇒ ProtoObject
ProtoObject superclass ⇒ nil


전통적으로, 스몰토크 상속 계층에서 최상위는 Object 클래스 입니다(모든 것이 객체이기 때문입니다). 스퀵에서, 최상위 요소는 실제로 ProtoObject 라고 불리는 클래스가 됩니다만, 일반적인 경우 당신이 이 클래스에 신경을 쓸 필요는 없습니다. ProtoObject는 모든 객체가 반드시 가져야 할 메시지의 최소한의 요소를 캡슐화 하고 있습니다. 그렇지만 대부분의 클래스는 ProtoObject가 아닌 Object 에게서 상속을 받으며, Object 에는 ProtoObject에 비해 대부분의 객체가 반드시 이해하고 응답해야 할 수많은 추가적인 메시지등이 정의되어 있습니다. 다른 방법을 써야 할 특별한 이유가 없다면, 프로그래밍으로 클래스를 만들때, 만들어지는 클래스는 Object 또는 Object 의 서브클래스 중 하나가 됩니다.


Squeak comment.png새로운 클래스는 일반적으로 subclass:instanceVariableNames:... 이라는 메시지를 보냄으로써 만들어집니다. 클래스를 만들기 위한 몇 가지 다른 메서드가 있습니다. 그 메서드들이 무엇인지는 프로토콜 Kernel-Classes ▷ Class ▷ subclass 을 보면 됩니다.


비록 스퀵은 다중 상속을 지원하지 않지만, 버전 3.9 이후로, 연관성없는 클래스들의 기능을 공유하기 위한 traits라 지칭되는 메커니즘이 추가되었습니다. Traits는 상속과 관련되지 않은 다중 클래스들에서 재사용할 수 있는 메서드들의 Collection입니다. Traits를 사용하면 코드를 복사할 필요없이, 다양한 클래스들 사이의 코드를 하나의 코드로 공유할 수 있습니다.[1]


추상 메서드와 추상 클래스

추상클래스는 인스턴스화된다기보다는 하위분류로 존재하는 클래스입니다. 추상 클래스는 그것이 사용하는 모든 메서드를 정의하지 않는다는 면에서,일반적으로 봤을때 완전한 클래스는 아닙니다. 이 경우 mission 메서드-다른메서드를 대상으로 하지만 메서드 자체(동작)가 정의되지 않은경우-는 추상메서드 라고 말합니다.

스몰토크는 메서드 또는 클래스를 abstract(추상)으로 지정하기 위한 문법은 별도로 없습니다. 관례적으로, 추상 메서드는 self subclassResponsibility 의 표현식으로 만들어져 있습니다. 이것은 "마커 메서드(marker method)" 로 알려져 있으며, 서브클래스가 메서드의 구체적인 내용을 정의해야한다는것을 나타냅니다. Self subclassResponsibility 메서드는 항상 재지정되므로, 절대로 실행하면 안됩니다. 만약 여러분이 재지정 하는 것을 잊어버리고, 그 메서드를 실행하면, 예외가 적용될 것입니다.

클래스는, 자신의 메서드들 중의 하나가 추상적인 경우, 추상 클래스로 분류됩니다. 여러분이 추상 클래스의 인스턴스를 만드는 것을 제한하는것은 아무것도 없으며, 추상 메서드를 실행하기 전 까지는 모든 것이 동작합니다.


예시 : Magnitude 클래스

Magnitude는 상호간 비교 가능 객체를 정의하는데 도움을 주는 추상 클래스입니다. Magnitude 의 서브클래스는 반드시 메서드 <, = 와 hash를 구현해야 합니다. 각각의 메시지를 사용하여, Magnitude 에 >, >=, <=, max:, min: between:and: 등 객체를 비교하기 위한 다른 메서드를 정의합니다. 이들 메서드는 서브클래스에서 상속받습니다. 메서드 < 은 추상 메서드이며 메서드 5.7에서 보시는 것처럼 정의합니다.


메서드5.7:Magnitude>> <

Magnitude>> < aMagnitude
  "수신자가 인자보다 작은지 응답합니다."
  self subclassResponsibility


반대로, 메서드 >= 는 메서드의 정의가 구체적입니다. < 에 대해 정의하였습니다:


메서드 5.8: Magnitude>> >=

>= aMagnitude
  "수신자가 인자보다 크거나 같은지 응답합니다."
  (self < aMagnitude) not

다른 비교 메서드의 true 반환도 같습니다.


Character는 Magnitude의 서브클래스입니다. Character클래스는 < 에 대한 자신의 버전을 갖기 위해 subclassResponsibility 메서드를 재정의합니다 (메서드 5.9를 보세요). Character는 또한 메서드 = 와 hash 를 정의하며, 메서드 >=, <=,~= 과 기타 등등을 Magnitude로부터 상속 받습니다.


메서드 5.9: Character>> <

Character>> < aCharacter
  "Answer true if the receiver's value < aCharacter's value."
  self asciiValue < aCharacter asciiValue


Traits

Trait은 상속이 필요없는 클래스의 동작을 포함할 수 있는 메서드의 Collection입니다. Trait은 여러 클래스가 유일한 super클래스를 쉽게 가지도록 하면서, 직접적 관련이 없는 클래스의 유용한 메서드를 공유하게 합니다.

새로운 trait을 정의하기 위해서는, 메시지에 의한 서브클래스 생성 템플릿을 Trait 클래스로 바꿔주기만 하면 됩니다.


클래스 5.10: 새로운 trait을 정의하기

Trait named: #TAuthor
  uses: { }
  category: 'SBE-Quinto'


카테고리 SBE-Quinto에서 TAuthor 를 trait 으로 정의하겠습니다. 이 trait은 다른 trait을 전혀 사용하지 않습니다. 일반적으로, uses: 라는 키워드 인수의 다른 특성을 사용할 수 있게 하는 Trait 합성구문 을 지정할 수 있습니다. 여기서는 단지, 빈 array를 제공합니다.

author 메서드를 클래스 계층도에서 독립적으로 취급하며 다양한 class에서 사용하게 할거라면, 다음과같이 작성하면 됩니다:


메서드 5.11: Author 메서드

TAuthor >> author
  "Returns author initials"
   'on' "oscar nierstrasz"


2장에서 정의한 SBEGame 클래스와 같이, 자체적으로 super클래스를 이미 보유한 클래스에서 이 trait을 사용할 수 있습니다. TAuthor를 사용하라고 지시하는 uses: 키워드 인자를 포함하기 위해 SBEGame의 클래스 생성 템플릿을 간단히 수정하겠습니다.


클래스 5.12: trait 사용하기

BorderedMorph subclass: #SBEGame
  uses: TAuthor
  instanceVariableNames: 'cells'
  classVariableNames: ''
  poolDictionaries: ''
  category: 'SBE-Quinto'


이제 SBEGame 을 인스턴스화 하는경우, 예상대로 author 메시지에 반응합니다.

SBEGame new author  'on'


Trait 합성 표현식은 + 연산자를 사용하여 여러 trait을 결합할 수 있습니다. 충돌이 생기는 경우(예를 들면, 여러 trait에서 같은 이름의 메서드를 정의할 경우), 이들 충돌 요소를 메서드 제거( - 기호)를 통해 깔끔하게 해결할 수 있으며, 또는 클래스 또는 trait의 메서드를 재 정의하여 해결할 수도 있습니다. 또한 (@ 기호) 메서드의 새 이름을 쓰려는 목적으로 메서드의 별칭alias을 사용할 수도 있습니다

Traits는 시스템 커널에서도 사용합니다. Behavior 클래스는 좋은 예제입니다.


클래스 5.13: traits을 사용하여 정의된 동작

Object subclass: #Behavior
  uses: TPureBehavior @ {#basicAddTraitSelector:withMethod: #addTraitSelector:withMethod:}
  instanceVariableNames: 'superclass methodDict format'
  classVariableNames: 'ObsoleteSubclasses'
  poolDictionaries: ''
  category: 'Kernel-Classes'


위의 예에서 addTraitSelector:withMethod: 라고 이름을 지정한 TPureBehavior 의 특성trait에 정의된 basicAddTraitSelector:withMethod: 를 확인할 수 있습니다. Trait 에 대한 지원은 현재 시스템 브라우저에 추가되고 있습니다.


Notes

  1. Ruby도 trait을 지원한다고 합니다. 이내용을 보면 꽤나 오래전부터 지원되었던 느낌인데요.. Ruby에서의 지원예를 보고싶다면 여기에서 trait을 검색해 참고하면 되겠습니다.