SqueakByExample:2.6

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

SBEGame 클래스 정의하기

이제 SBEGame 이라고 이름붙일 게임에 필요한 다른 클래스를 만들어보도록 하겠습니다.


Squeak comment.png브라우저 메인 창에서 클래스 정의 템플릿을 보이게 하십시오.


이미 선택한 클래스 카테고리의 이름을 두 번 클릭하거나, (instance 버튼을 클릭하여)SBECell의 정의를 보이게 하십시오. 다음과 같이 코드를 편집하고 accept 하십시오.


클래스 2.3: SBEGame 클래스 정의

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


이제 BoderedMorph의 하위클래스를 만들 차례입니다.[1] Morph 는 스퀵의 모든 그래픽 도형에 대한 상위클래스가 되며(놀랍군요!), BorderedMorph 는 테두리를 가진 Morph 입니다. 두번째 줄의 따옴표 사이에 인스턴스 변수의 이름을 넣을 수도 있겠지만, 지금은 그냥 빈 목록으로 남겨 놓겠습니다.

자 이제 SBEGame에 대한 initialize 메서드를 정의하도록 하겠습니다.


Squeak comment.pngSBEGame에 대한 메서드를 브라우저에 다음과 같이 입력하고, accept 해보십시오:


메서드 2.4: 게임 초기화

initialize
  | sampleCell width height n |
  super initialize.
  n := self cellsPerSide.
  sampleCell := SBECell new.
  width := sampleCell width.
  height := sampleCell height.
  self bounds: (5@5 extent: ((width*n) @(height*n)) + (2 * self borderWidth)).
  cells := Matrix new: n tabulate: [ :i :j | self newCellAt: i at: j ].


스퀵은 일부 용어의 의미를 모른다고 불평할 것입니다. 스퀵은 CellsPerSide 메시지를 모른다고 할 것이며, 대신하기 위한 수많은 컬렉션을 제안할텐데, 이 경우에는 철자 오류가 있습니다.


UnknownSelector.png DeclareInstanceVar.png
그림 2.8 알려지지 않은 selector를 감지한 스퀵 그림 2.9: 새로운 인스턴스 변수 선언하기


하지만 cellsPerSide 는 잘못 입력한 것이 아닙니다. ---아직 정의하지 않은 메서드일 뿐입니다--- 짧은 시간 안에 메서드를 정의해보겠습니다.


Squeak comment.png메뉴에서 첫 번째 항목을 선택하면 cellsPerside 를 실제로 의미했음을 확인할 수 있습니다.


다음차례로, 스퀵은 cells 의 의미를 모른다고 불평할 것입니다. 이런 문제를 수정하기 위한 수많은 방법이 제공됩니다.


Squeak comment.pngcells 를 인스턴스 변수로 만들 것이므로, declare instance 를 선택하십시오.


마지막으로, 스퀵은 마지막 줄에서 보낸 newCellAt:at: 메시지에 대해 불평할 것입니다. 이것도 실수가 아니기 때문에 메시지를 확인하기 바랍니다.

클래스 정의를 다시 한 번 살펴보면(instance 버튼을 클릭하면 실행할 수 있음), Browser 가 인스턴스 변수인 cells 를 포함하도록 클래스의 정의를 수정[2]했다는 것을 알 수 있습니다.


이제 initialize 메서드를 살펴 보겠습니다. | sampleCell width height n | 줄에서는 임시로 4개의 변수를 선언합니다. 변수의 범위와 수명이 메서드에 국한되기 때문에 임시 변수temporary variables라고 부르도록 하겠습니다. 설명이 잘 되어있는 이름이 붙은 임시 변수는 코드 가독성을 더 좋게 하는데 도움이 됩니다. Smalltalk 에는 상수와 변수를 구분하기 위한 특별한 문법이 없으며, 사실 이 네 개의 모든"변수“variables”"는 사실 상수입니다. 4-7 번째 줄은 이들 상수를 정의합니다.


게임판은 얼마나 커야 할까요? 몇몇 정수 크기만큼의 cell 을 담기에 충분히 크고, 그 cell 주위에 경계를 그리기에 충분할만큼 커야 합니다. cell 의 갯수는 얼마정도가 적당할까요? 5? 10? 100? 아직은 모르지만, 이미 알고 있다고 해도, 나중에 변경하게 될지 모르겠군요. 그렇기 때문에, 이러한 숫자를 알아야 하는 책임을 다른 메서드로 위임하려 합니다. 이 메서드는 cellsPerSide 라는 이름을 가지며, 1~2 분 사이에 작성하려 합니다.

initialize 메서드에 대한 내용을 accept 했을 때, "확인(confirm), 수정(correct) 또는 취소(cancel)" 를 물어보는 다이얼로그가 뜨게되는데, 이런 현상은 스퀵이 요청한 이름을 가진 메서드가 정의되지도 않았을때, cellsPerSide 라는 메시지를 보내기 때문입니다. 걱정하지 마세요. 이런 방법은 아직 정의되지 않은 다른 메서드로 작업을 진행하는 좋은 방법입니다. 왜 일까요? 글쎄요, initialize 메서드를 작성하기 전에 먼저 필요성을 느낀것도 아니기 때문에, 상황이 발생되었을때 의미있는 이름을 부여하고 작업의 흐름을 방해하지 않고 작업을 계속 진행할 수 있습니다.


네번째 줄은 이렇게 정의된 cellsPerSide 메서드를 사용합니다. 스몰토크에서 self cellsPerSide 는 cellsPerSide 메시지를 나 자신(SBEGame)을 의미하는 객체인 self 에 보냅니다. 게임판의 각 모서리당 cell 의 갯수 응답을 n 에 할당합니다.


그 다음의 세 줄에서는, 새로운 SBECell 객체를 만들고, 객체의 너비와 높이를 적당한 임시 변수에 넣습니다.


여덟번째 줄은 새로운 객체의 bounds 를 설정합니다. 세부적인 내용에 대한것은 걱정할 필요가 없으며, 괄호 안에 있는 표현이 point (5,5) 와 그 하단 오른쪽 모서리에 원점orign을 둔 정사각형(즉, 왼쪽 위)을 만든다고 믿으십시오. 적절한 개수의 cell 이 있는 공간을 허용하려는 목적에 맞게 충분하게 멀리 떨어져 있습니다.


마지막 줄은 SBEGame 객체의 인스턴스 변수인 cells 에 올바른 행과 열의 개수대로 새로 만든 Matrix 를 할당합니다. Matrix 클래스(클래스도 객체이므로, 메시지를 보낼 수 있습니다)에 new:tabulate: 메시지를 보내서 처리했습니다. new:tabulate: 의 이름에 두 개의 콜론(:)이 있는걸 보면, 이 메서드는 인자를 두 개 받는다는걸 알 수 있습니다. 인자는 콜론 바로 다음에 위치하게 됩니다. 만약 당신이 인자를 모두 괄호 안에 넣는 프로그래밍 언어를 사용해 왔었다면, 이 표기법은 매우 이상하게 느껴질 것입니다. 당황하지 마세요, 이것은 단지 문법일 뿐입니다! 이런 방법은 메서드의 이름으로 인자의 역할을 설명하는데 활용할 수 있기 때문에, 상당히 좋은 문법으로 알려져 있습니다. 예를 들어, Matrix rows: 5 columns: 2 는 5개의 가로 열과 2개의 세로 열을 갖는 것이지 2개의 가로 열과 5개의 세로 행을 가진 것이 아니라는 점을 확실히 알게 해줍니다.


Matrix n tabulate: [ :i :j | self newCellAt: i at: j ] 은 새로운 n x n 2차원 배열을 만들고 요소를 초기화합니다. 각각의 초기 값은 좌표에 따라 다릅니다. (i,j)번째 요소는 newCellAt: i at: j. 처리 결과로 초기화합니다.

지금까지의 내용이 바로 initialize 입니다. 이 메시지 내용을 accept 하면, 아마도 작성한 코드를 가지런히 다듬고(pretty-up formating) 싶을 것입니다. 직접 일일히 할 필요는 없고, 노랑-버튼 메뉴에서, more▷prettyprint를 선택하면, 사용자를 위해 브라우저가 알아서 해줄 것입니다. 메서드를 깔끔하게 출력하고 난 후에, 다시 accept 하거나, 결과가 맘에 들지 않으면 물론 취소 (CMD-l 숫자 1이 아닌 L의 소문자입니다)할 수 있습니다. 대신, 코드가 보일때는 언제나 pretty-printer 를 브라우저가 사용하도록 설정할 수도 있습니다. 보이는 것을 조절하려면 버튼 표시줄에서 가장 오른쪽 버튼을 사용하십시오.


more... 를 더 많이 사용하신다면, more... 를 직접 불러오려고 클릭할 때 Shift 키를 누른 채로 클릭하면 그 상태가 유지된다는 것을 알고 계시는 것이 좋습니다.


Notes

  1. Package 는 이럴 때 유용합니다. 여러 개의 클래스를 하나로 묶어둡니다. 각각의 상위클래스가 서로 다른 여러개의 클래스를 같은 패키지로 묶어서 라이브러리처럼 관리합니다
  2. Class가 정의된 부분을 보면 instanceValirableNames 부분에 cells가 추가된것을 확인할 수 있습니다