SqueakByExample:8.1: Difference between revisions

From 흡혈양파의 번역工房
Jump to navigation Jump to search
(SBE 오브젝트 페이지 추가)
 
mNo edit summary
Line 7: Line 7:


오브젝트 상태(the object states)에 대한 클래스 주석:<br>
오브젝트 상태(the object states)에 대한 클래스 주석:<br>
''오브젝트는 클래스 계층도에 있는 거의 모든 다른 클래스들을 위한 루트 클래스(the root class)입니다. 예외는 {{Template:HighlightBold|ProtoObject}}(오브젝트의 superclass)와 그것의 서브클래스들(subclases)입니다. 클래스 {{Template:HighlightBold|오브젝트(Object)}}는 접근(access), 복사(copying), 비교(comparison), 에러 헨들링(error handling), 메시지 발송(message sending), 그리고 반영(reflection)과 같은 모든 보통 {{Template:HighlightBold|오브젝트(Object)}}에 공통인 디폴트 동작(default behaviour)을 제공합니다. 또한 모든 오브젝트들이 응답해야할 유틸리티 메시지들(utility messages)은 이곳에서 정의됩니다. 오브젝트는 인스턴스 변수를 갖고 있지 않을 뿐만 아니라, 어떤 것도 그 자체에 추가될 수 없습니다. 이러한 현상은 오브젝트의 여러 클래스들이 특별한 실행(예를 들면 {{Template:HighlightBold|smallInteger}} 와 {{Template:HighlightBold|UndefinedObject}})을 갖는 오브젝트로부터 상속되었기 때문이거나 또는 VM이 특정한 표준 클래스(standard classes)의 구조와 레이아웃에 관해 알거나 기초해 있기 때문입니다.''
''오브젝트는 클래스 계층도에 있는 거의 모든 다른 클래스들을 위한 루트 클래스(the root class)입니다. 예외는 {{Template:HighlightBold|ProtoObject}}(오브젝트의 superclass)와 그것의 서브클래스들(subclases)입니다. 클래스 {{Template:HighlightBold|Object}}는 접근(access), 복사(copying), 비교(comparison), 에러 헨들링(error handling), 메시지 발송(message sending), 그리고 반영(reflection)과 같은 모든 보통 {{Template:HighlightBold|오브젝트}}에 공통인 디폴트 동작(default behaviour)을 제공합니다. 또한 모든 오브젝트들이 응답해야할 유틸리티 메시지들(utility messages)은 이곳에서 정의됩니다. 오브젝트는 인스턴스 변수를 갖고 있지 않을 뿐만 아니라, 어떤 것도 그 자체에 추가될 수 없습니다. 이러한 현상은 오브젝트의 여러 클래스들이 특별한 실행(예를 들면 {{Template:HighlightBold|smallInteger}} 와 {{Template:HighlightBold|UndefinedObject}})을 갖는 오브젝트로부터 상속되었기 때문이거나 또는 VM이 특정한 표준 클래스(standard classes)의 구조와 레이아웃에 관해 알거나 기초해 있기 때문입니다.''





Revision as of 04:17, 30 August 2012

오브젝트 (Object)

오브젝트는 모든 의도와 목적에 있어 상속 계층도(the inheritance hierarchy)의 근간(root)입니다. 실제로 스몰토크에서, 상속도의 참된 근간은(the true root) ProtoObject이며, 이것은 오브젝트로서 가장된 최소한의 엔티티들(minimal entities)을 정의하기 위해 사용되지만, 우리는 지금 이러한 기능을 무시할 수 있습니다.

오브젝트는 커널-오브젝트 카테고리(the Kernel-Objects category)에서 발견될 수 있습니다. 놀랍게도, 여기서 발견될 (확장포함) 400개의 메소드가 있습니다. 다른 말로 하면, 여러분이 정의하는 모든 클래스는 여러분이 그 메소드들을 아는 여부와 상관 없이 400개의 메소드를 자동으로 제공한다는 것입니다. 이 메소드들의 몇몇은 반드시 제거되야 하며 스퀵의 새로운 버전은 아마도 더 이상 필요하지 않은 메소드들을 제거할 수도 있습니다.


오브젝트 상태(the object states)에 대한 클래스 주석:
오브젝트는 클래스 계층도에 있는 거의 모든 다른 클래스들을 위한 루트 클래스(the root class)입니다. 예외는 ProtoObject(오브젝트의 superclass)와 그것의 서브클래스들(subclases)입니다. 클래스 Object는 접근(access), 복사(copying), 비교(comparison), 에러 헨들링(error handling), 메시지 발송(message sending), 그리고 반영(reflection)과 같은 모든 보통 오브젝트에 공통인 디폴트 동작(default behaviour)을 제공합니다. 또한 모든 오브젝트들이 응답해야할 유틸리티 메시지들(utility messages)은 이곳에서 정의됩니다. 오브젝트는 인스턴스 변수를 갖고 있지 않을 뿐만 아니라, 어떤 것도 그 자체에 추가될 수 없습니다. 이러한 현상은 오브젝트의 여러 클래스들이 특별한 실행(예를 들면 smallIntegerUndefinedObject)을 갖는 오브젝트로부터 상속되었기 때문이거나 또는 VM이 특정한 표준 클래스(standard classes)의 구조와 레이아웃에 관해 알거나 기초해 있기 때문입니다.


만약 우리가 오브젝트의 인스턴스 사이드(the instance side)에서 메소드 카테고리 검색을 시작한다면, 그것이 제공하는 매우 중요한 동작의 몇 가지들을 보기 시작할 것입니다.

인쇄(Printing)

스몰토크에서 모든 오브젝트들은 그 자체의 인쇄된 폼(a printed form)을 리턴할 수 있습니다. 여러분은 워크스페이스에서 모든 표현식(expression)을 선택할 수 있고 print it 메뉴를 선택할 수 있습니다: 이 동작은 표현식을 실행하고 리턴된 오브젝트에게 그 자체를 인쇄하도록 요청합니다. 사실 이 동작은 리턴된 오브젝트에 메시지 printString을 발송합니다. 메소드 printString은 템플릿 메소드(a template method)이며 그 자체 코어는 메시지 printOn:을 그 자신의 수신자(receiver)에 발송합니다. 메시지 printOn:은 특화될 수 있는 hook입니다.

Object»printOn:은 여러분이 가장 빈번하게 재지정(override)할 수 있을만한 메소드들 중의 하나일 가능성이 높습니다. 이 메소드는 오브젝트의 문자열 표현이 작성될 그 메소드의 인수로서 a Stream을 취합니다. 디폴트 실행(the default implementation)은 단순히 “a” 또는 “an” 뒤에 클래스 이름을 적습니다. Object»printString은 작성된 문자열을 리턴 합니다.

예를 들면, 클래스 브라우저(the class Browser)는 메소드 printOn:을 재정의 하지(redefine) 않으며 메시지 printSting을 오브젝트에서 정의된 메소드들을 실행하는 인스턴스에 발송합니다.


Browser new printString  'a Browser'


클래스 TTCFont는 PrintOn: 특별화(specialization)의 예시를 보여드립니다. 클래스의 인스턴스를 인쇄하는 아래의 코드에 보이는 것처럼, 폰트의 가족 이름(the family name), 크기(the size) 그리고 종속 가족 이름(subfamily name)이 클래스 이름 뒤를 잇습니다.


메소드 8.1: printOn: 재정의

TTCFont»printOn: aStream
  aStream nextPutAll: 'TTCFont(';
  nextPutAll: self familyName; space;
  print: self pointSize; space;
  nextPutAll: self subfamilyName;
  nextPut: $)
TTCFont allInstances anyOne printString       'TTCFont(BitstreamVeraSans 6 Bold)'

메시지 PrintOn:은 storeOn:과 동일하지 않다는 것에 주의합니다. 메시지 StoreOn은 수신자(the receiver)를 다시 만들기 위해 사용될 수 있는 표현식을 그 자체의(Storeon의)인수에 넣습니다. 이 표현식은 메시지 readFrom을 사용하여 읽힐 때 평가됩니다. pringOn:은 단지 수신자의 원문의 버전(a textual version)을 리턴합니다. 물론 원문의 표현(textual representation)이 자체 평가 표현식(a self-evaluating expression)으로서 수신자를 나타내는 일이 생길 수 있습니다.


표현과 자체 평가 표현에(representation and self-evaluating representation) 관한 단어 기능 프로그래밍에서, 표현식은 실행될 때 값을 리턴합니다. 스몰토크에서, 메시지들은 (표현식) 오브젝트(값)을 리턴합니다. 몇몇 오브젝트는 그 값이 그 자체들인 훌륭한 속성(properties)들을 갖고 있습니다. 예를 들면, 오브젝트 true의 값은 예컨데 오브젝트 true인 그 자체입니다. 우리는 이러한 오브젝트를 자체 평가 오브젝트(self-evaluating object)라 부릅니다. 여러분은 워크스페이스에서 오브젝트를 인쇄할 때 오브젝트의 인쇄된 버전을 볼 수 있습니다. 여기에 이러한 자체 평가 표현식의 예시가 있습니다.

true ⇒ true
3@4 ⇒ 3@4
$a ⇒ $a
#(1 2 3) ⇒ #(1 2 3)


배열(arrays)과 같은 몇몇 오브젝트는 자체 평가이거나 또는 그것들이 포함하고 있는 오브젝트에 의존하지 않는 다는 사실에 주의합니다. 예를 들면, 불리언(Booleans)의 배열은 자체평가인 반면 persons의 배열은 그렇지 않습니다. 스퀵 3.9에서 메커니즘은 가능한 많이 자체 평가 폼(self-evaluating forms)속에 컬렉션들(collections)을 인쇄하기 위해 소개되었고, 이는 특별히 중괄호 배열에 있어 참입니다. 다음 예시는 동적 배열의 구성요소들일 경우에만, 동적 배열이 자체평가가 되는 것을 보여드립니다.


{10@10 . 100@100} ⇒ {10@10 . 100@100}
{Browser new . 100@100} ⇒ an Array(a Browser 100@100)


리터럴 배열(literal arrays)들이 오직 리터럴만(literal) 포함한다는 사실을 기억하십시오. 그러므로 다음 배열은 두 개의 점(two points)를 포함하지 않으며 여섯개의 리터럴 구성요소만을 포함합니다.


#(10@10 100@100) ⇒ #(10 #@ 10 100 #@ 100)


많은 printOn: 메소드 특별화들은(method specializations)는 자체 평가 동작을 실행합니다. Point»printOn:와 Interval»printOn:의 실행은 자체 평가입니다


메소드 8.2: Point의 자체 평가(Self-evaluation)

Point»printOn: aStream
  "The receiver prints on aStream in terms of infix notation."
  x printOn: aStream.
  aStream nextPut: $@.
  y printOn: aStream


메소드 8.3:인터벌(Interval)의 자체평가(Self-evaluation)

Interval»printOn: aStream
  aStream nextPut: $(;
    print: start;
    nextPutAll: ' to: ';
    print: stop.
  step = 1 ifTrue: [aStream nextPutAll: ' by: '; print: step].
  aStream nextPut: $)
1 to: 10  (1 to: 10)  "intervals are self--evaluating"


정체성(identity)과 동등성(equality)

스몰토크에서, 메시지=테스트 오브젝트의 동등성(예컨데, 두 개의 오브젝트가 동일한 값을 나타내는 것과 상관없이)이며, 반면에 ==는 오브젝트 정체성을 테스트합니다. (예컨데 두 개의 표현식이 동일한 오브젝트를 나타내는 것과 상관없이)


오브젝트 동등성의 디폴트 실행은 오브젝트 정체성을 위한 테스트를 시행하는 것입니다.


메소드 8.4: 오브젝트 동등성(Object equality)

Object»= anObject
  "Answer whether the receiver and the argument represent the same object.
  If = is redefined in any subclass, consider also redefining the message hash."
   self == anObject


이것은 여러분이 빈번하게 재지정(override)하기를 원하는 메소드 입니다. 복합적인 숫자들(numbers)의 사례를 고려해 보십시오:


(1 + 2 i) = (1 + 2 i) ⇒ true "same value"
(1 + 2 i) == (1 + 2 i) ⇒ false "but different objects"


이것은 작동합니다. 그 이유는 복합적인 재지정(complex override)이 다음과 같기 때문입니다


메소드 8.5: 복합 숫자들(complex numbers)를 위한 동등성(Equlity)

Complex»= anObject
  anObject isComplex
    ifTrue: [ (real = anObject real) & (imaginary = anObject imaginary)]
    ifFalse: [ anObject adaptToComplex: self andSend: #=]


Object»~=의 실행은 단순히 Object»=를 무효로 하며, 일반적인 상황에서 변경될 필요가 없습니다.

(1 + 2 i) = (1 + 4 i)  true


만약 여러분이 =를 재지정하면, hash 재지정을 고려해야만 합니다. 만약 여러분의 클래스의 인스턴스가 딕셔너리에서 키들(keys)로 사용된 적이 없다면, 인스턴스를 동일한 hash 값을 갖는 것과 동등하게 고려가되도록 제작해야만 합니다:


메소드 8.6: hash는 반드시 복합 숫자들을 위해 재실행되어야 합니다.

Complex»hash
  "Hash is reimplemented because = is implemented."
   real hash bitXor: imaginary hash.


비록 여러분이 =과 hash를 함께 재지정 해야만 할지라도, ==는 결코 재지정하면 안됩니다. (오브젝트 정체성의 의미론은 모든 클래스에 동일합니다) ==은 ProtoObject의 프리미티브 메소드(primitive method)입니다.

스퀵이 다른 스몰토크와 비교하여 몇 가지 이상한 동작(behaviour)를 갖고 있는 것에 주목해 주십시오: 예를 들면, 심볼(symbol)과 문자열(string)은 동등해 질 수 없습니다 [우리는 이것을 bug로 고려하며, 특성(feature)으로 고려하지 않습니다]


#'lulu' = 'lulu'    true
'lulu' = #'lulu'    true


클래스 멤버십(Class membership)

여러 개의 메소드는 여러분으로 하여금 오브젝트의 클래스를 조회(query)할 수 있도록 해드립니다.

클래스. 여러분은 메시지 클래스(the message class)를 사용하여 오브텍트의 클래스에 관해 모든 객체들에게 요청을 할 수 있습니다.

1 class    ⇒    SmallInteger


반대로, 여러분은 오브젝트가 특정 클래스의 인스턴스 인지의 여부에 대한 확인을 요청할 수도 있습니다:

1 isMemberOf: SmallInteger ⇒ true "must be precisely this class"
1 isMemberOf: Integer ⇒ false
1 isMemberOf: Number ⇒ false
1 isMemberOf: Object ⇒ false


스몰토크가 그 자신에게서 작성되었기 때문에, 여러분은 superclass와 클래스 메시지(12장을 보십시오)의 올바른 조합을 사용하여 스몰토크의 구조 전체를 실제로 탐색할 수 있습니다.


isKindOf: Object»isKindOf:는 수신자(the receiver)의 클래스를 동일한 것 또는 인수 클래스 의 서브클래스로서 답변합니다.

1 isKindOf: SmallInteger ⇒ true
1 isKindOf: Integer ⇒ true
1 isKindOf: Number ⇒ true
1 isKindOf: Object ⇒ true
1 isKindOf: String ⇒ false
1/3 isKindOf: Number ⇒ true
1/3 isKindOf: Integer ⇒ false

1/3은 분수인 동시에 숫자의 한 종류이며, 클래스 숫자가 클래스 분수의 superclass이지만 1/3은 정수가 아닙니다.


respondsTo: Object»respondsTo:은 인수로서 주어진 메시지 선택자(the message selector)를 수신자(the receiver)가 이해하는지의 여부로 답변합니다.

1 respondsTo: #, ⇒  false


보통 오브젝트의 클래스를 위해 오브젝트를 조회(query)하거나 오브젝트가 어떤 메시지를 이해하는지를 오브젝트에게 요청하는 것은 좋지 않은 생각입니다. 여러분은 오브젝트의 클래스에 기초하여 결정을 하는 대신에, 단순히 오브젝트에 메시지를 발송하여야만 하며, 그 오브젝트가 어떻게 작동해야만 할지를 스스로 결정하도록(예컨데 오브젝트의 클래스에 기초하여) 해야 합니다.


복사(Copying)

오브젝트를 복사하는 것은 몇 가지 미묘한 문제들을 낳습니다. 인스턴스 변수들이 참조(reference)에 의해 접근되기 때문에, 오브젝트의 오브젝트의 얕은 복사(shallow copy)는 인스턴스 변수에 대한 그 오브젝트의 참조를 오리지널 오브젝트와 공유합니다:


a1 := { { 'harry' } }.  
a1 ⇒ #(#('harry'))
a2 := a1 shallowCopy.  
a2 ⇒ #(#('harry'))
(a1 at: 1) at: 1 put: 'sally'.  
a1 ⇒ #(#('sally'))
a2 ⇒ #(#('sally')) "the subarray is shared"


Object»shallowCopy 는 오브젝트의 얕은 복사(shallow copy)를 만드는 프리미티브 메소드(primitive method)입니다. a2가 a1의 유일한 얕은 복사이므로, 두 개의 배열은 그것들이 포함하고 있는 상주하는 배열(the nested array)에 대한 참조를 공유합니다.


Object»shallowCopy 는 Object»copy에 대한 “public interface(공용 인터페이스)”이며 만약 인스턴스들이 고유한(unique)것들일 경우 반드시 재지정(overridden) 되어야만 합니다. 이것은 케이스(case)입니다. 예를 들면 클래스 불리언(Boolean), 문자(Character), Smallinteger, 심볼(Symbol) 그리고 UndefinedObject와 함께있는경우,


Object»copyTwoLevel은 단순한 얕은 복사(simple shallow copy)가 만족시키지 못할 때, 명확한 작업을 수행합니다:

a1 := { { 'harry' } } .  
a2 := a1 copyTwoLevel.  
(a1 at: 1) at: 1 put: 'sally'.  
a1 ⇒ #(#('sally'))
a2 ⇒ #(#('harry')) "fully independent state"


Object»deepCopy 는 임의로 오브젝트의 깊은 복사(deep copy)를 만듭니다.

a1 := { { { 'harry' } } } .  
a2 := a1 deepCopy.  
(a1 at: 1) at: 1 put: 'sally'.  
a1 ⇒ #(#('sally'))
a2 ⇒ #(#(#('harry')))


깊은복사(deepCopy)의 문제는 상호간의 귀납적인 구조(mutually recursive structure)에 적용될 때, 종료되지 않는다는 것입니다:

a1 := { 'harry' }.  
a2 := { a1 }.  
a1 at: 1 put: a2.  
a1 deepCopy ⇒ ...does not terminate!


비록, 깊은 복사(deepCopy) 재지정이 바른 작업을 하는 것이 가능하지만, Object»는 더 나은 솔루션을 우리에게 제공합니다:


메소드 8.7: 템플릿 메소드(template method)로서 오브젝트를 복사하기

Object»copy
  "Answer another instance just like the receiver. Subclasses typically override
    postCopy;
  they typically do not override shallowCopy."
  self shallowCopy postCopy


공유되지 않아야 할 모든 인스턴스 변수들을 복사하기 위해 여러분은 반드시 postCopy를 재지정(override)해야만 합니다. posetCopy는 반드시 super postCopy를 실행해야만 합니다.


디버깅(Debugging)

여기서 가장 중요한 메소드는 halt입니다. 메소드에서 breakpoint를 설정하기 위해, 메소드의 바디에 있는 몇몇 점(point)에 메시지 발송(message send) self halt”를 삽입합니다. 메시지가 발송될 때, 실행은 간섭되며, 디버거는 여러분의 프로그램에서 이 지점(point)에 열릴 것입니다. (디버거에 관한 좀더 상세한 내용은 6장을 보십시오.)

다음 중요한 메시지는 assert:이며, 이 메시지는 그 자체의 인수로서 블록(block)을 취합니다 만약 블록이 true를 리턴하면 실행이 계속됩니다. 그렇지 않을 경우, AssertionFailure 예외(exception)가 제기될 것입니다. 만약 이 예외가 별도로 잡히지 않으면, 디버거는 실행시 이 지점(point)에서 열릴 것입니다. assert:는 계약(contract)에 의해 디자인을 지원하는 작업에 특별히 유용합니다. 가장 전형적인 용례는 오브젝트의 공용 메소드(public methods)에 대한 사소하지 않은 전제조건(non-trivial pre-conditions)을 점검하는 작업에 쓰이는 것입니다. Stack»pop는 다음과 같이 쉽게 실행될 수 있습니다.


메소드 8.8: 전제조건 점검 (Checking a pre-condition)

Stack»pop
  "Return the first element and remove it from the stack."
  self assert: [ self isEmpty not ].
  self linkedList removeFirst element


TestCase»assert:로 Object»assert:을 혼돈하지 마십시오, 이것은 SUnit 테스트 프레임워크에서 발생합니다. (7장을 보십시오) 전자가 그것의 인수[1]로서 블록을 기대하는 반면에, 후자는 불리언(Boolean)을 기대합니다. 비록 두 개 모두 디버깅에 유용하지만, 매우 다른 용도로 쓰입니다.


에러 핸들링(Error handling)

이 프로토콜은 런타임 에러에 유용한 여러 개의 메소드들을 포함하고 있습니다.

만약, deprecation이 프리퍼런스 브라우저(Preference browser)의 디버그 프로토콜에서 켜진다면, 현재 메소드인 self deprecated: anExplanationString 신호 발송은 더 이상 사용되어서는 안됩니다. 문자열 인수(the String argument)는 반드시 대안(alternative)를 제공해야만 합니다.

1 doIfNotNil: [ :arg | arg printString, ' is not nil' ]
       SmallInteger(Object)»doIfNotNil: has been deprecated. use ifNotNilDo:


doesNotUnderstand: 는 메시지 lookup이 실패할 때마다 발송됩니다. 디폴트 실행은 예컨대, Object»doesNotUnderstand:가 이 지점에서 디버거를 트리거 하게 될 것입니다. 몇 가지 다른 동작을 제공하기 위해 doestNotUnderstand:를 재지정(override)하는 것은 유용할 수 있습니다.

Object»error 와 Object»error:는 예외들(exceptions)를 제기하기 위해 사용될 수 있는 포괄적인 메소드들(generic methods)입니다. 일반적으로, 여러분 자신의 사용자화된 예외들을 제기하는 것이 나으므로, 여러분의 코드에서 생긴 에러들과 커널 클래스들(kernel clases)에서 생긴 에러들을 구별할 수 있을 것입니다.

스몰토크에서 추상 메소드(Abstract methods)는 바디 self subclassResponsibility 와 함께 관례(convention)에 의해 실행됩니다. 추상 클래스(abstract class)는 우연히 예시되어야만 하며, 그 다음 추상 메소드에 대한 콜은 평가중인 Object»subclassResponsibility를 결과물로 내놓을 것입니다.


메소드 8.9: 메소드인 시그널링(signaling)은 추상 메소드입니다.

Object»subclassResponsibility
  "This message sets up a framework for the behavior of the class' subclasses.
  Announce that the subclass should have implemented this message."
  self error: 'My subclass should have overridden ', thisContext sender selector
    printString


매그니튜드(혹은 등급, Magnitude), 숫자(Number) 그리고 불리언(Boolean)은 우리가 이번 장에서 잠깐 살펴볼 추상 클래스들의 고전적인 예들입니다.

Number new + 1        ''Error: My subclass should have overridden #+''


'self ShouldNotImplement는 관례에(convention) 의해 상속된 메소드인 시그널에 발송되었고, 그 발송은 이 서브클래스에 적합하지 않습니다. 이것은 일반적으로 클래스 계층도의 디자인과 꽤 잘맞지 않는 어떤 신호(sign)입니다. 그럼에도 불구하고 단일 상속의 한계 때문에, 때때로 이러한 예비수단(workarounds)을 피하는 것이 매우 어렵습니다.

전형적인 예는 딕셔너리에 의해 상속되었지만 실행된 것으로 알려지지 않은 Collection»remove:입니다. (딕셔너리는 removeKey:instead를 제공합니다.)

Testing

testing 메소드는 SUnit 테스트와는 아무 관계가 없습니다. testing 메소드는 여러분에게 수신자(receiver)의 상태에 관한 질문을 하도록 해주고 불리언(Boolean)을 리턴하는 메소드입니다.

여러 개의 testing 메소드가 오브젝트에 의해 제공됩니다 우리는 이미 isComplex를 보았습니다. 다른 것들은 isArray, isBoolean, isBlock, isCollection 등을 포함합니다. 일반적으로 이러한 메소드들은 회피되어야 합니다. 그 이유는 메소드의 클래스를 위해 오브젝트를 조회(quering)하는 작업은 인켑슐레이션(encapsulation)의 위배 폼(a form of violation)입니다. 사용자는 오브젝트의 클래스를 테스트 하는 대신에, 요청(request)을 반드시 보내어 오브젝트로 하여금, 어떻게 그 클래스를 핸들 할지를 결정하도록 만들어야 합니다.

그럼에도 불구하고, 이 테스트 메소드들의 몇몇은 부인할 수 없을 만큼 유용합니다. 가장 유용한 것은 아마도 ProtoObject»isNil 과 Object»notNil 입니다 (비록 Null 오브젝트[2] 디자인 패턴(Object design pattern)이 심지어 이 메소드들을 위한 필요를 제거할 수 있기 때문입니다.


릴리즈 초기화 하기 (Initialize release)

ProtoObject에 있는 오브젝트에서 발생하지 않는 최종 키 메소드(final key method)는 initialize(초기화)입니다.


메소드 8.10: 빈 hook 메소드로서의 initialize(초기화)

ProtoObject»initialize
  "Subclasses should redefine this method to perform initializations on instance
  creation"


이것이 중요한 이유는 버전 3.9로서의 스퀵에서, 시스템에 있는 모든 클래스들을 위해 정의된 디폴트 새 메소드는(default new method) 새롭게 만든 인스턴스에 초기화(initialize)를 발송할 것이기 때문입니다.


메소드 8.11: 클래스-사이드 템플릿 메소드(class-side template method)로서의 new

Behavior»new
  "Answer a new initialized instance of the receiver (which is a class) with no
    indexable
  variables. Fail if the class is indexable."
   self basicNew initialize


이 의미는 initialize hook 메소드를 단순히 재지정하여 여러분의 클래스의 인스턴스들이 자동으로 초기화(initialized)된다는 것입니다. initialize 메소드는 반드시 모든 상속된 인스턴스 변수들을 위한 클래스 불변성(the class invariant)를 구축하기 위해 보통 super initialize를 수행합니다. (이것이 다른 스몰토크들의 표준 동작이 아닌 것에 주의해야 합니다)


Notes

  1. 실제로, 이것은 불리언을 포함한 값을 이해하는 모든 인수를 취할 것입니다.
  2. BobbyWoolf, Null Object. In Robert Martin, Dirk Riehle and Frank Buschmann, editors, Pattern Languages of Program Design 3. Addison Wesley, 1998