SqueakByExample:5.7

From 흡혈양파의 번역工房
Revision as of 09:58, 7 March 2013 by Onionmixer (talk | contribs) (주숵추가)
Jump to navigation Jump to search

공유 변수

이제 다섯 가지 규칙이 잘 적용되지 않는 스몰토크의 다른부분을 살펴보겠습니다 : 공유변수Shared variables 입니다.

스몰토크는 3가지 종류의 공유변수가 있습니다: (1) 전역 공유 변수 (2) 인스턴스와 클래스 사이에서 공유되는 변수(클래스 변수) 그리고 (3)클래스의 그룹(Category) 사이에서 공유된 변수(pool 변수)들. 이 세가지의 공유변수들은 사용자에게, 이 변수들은 공유된 변수라는 것을 알려주기 위해 대문자로 시작됩니다.


전역 변수

스퀵에서, 모든 전역 변수는 클래스 SystemDictionary 의 인스턴스로서 실행되며, Smalltalk 라고 불리는 네임스페이스에 저장됩니다. 스몰토크의 전역 변수는 어디서나 접근이 가능합니다. 모든 클래스는 전역변수같은 형식의 이름을 가지게 됩니다.[1] 덧붙이자면, 몇가지 이름은 특별한 작업 또는 일반적으로 유용한 오브젝트의 이름으로 미리 사용됩니다.

Transcript 는 스크롤 창에 데이터를 기록하는 스트림인 TranscriptStream 인스턴스를 가리키는데 사용되는 변수명 입니다. 다음코드는 Transcript에 정보를 표시하고 표시커서를 다음줄로 이동시킵니다.

Transcript show: 'Squeak is fun and powerful' ; cr

do it 을 클릭하기 전에, Tool 플랩 에서 Transcript를 드래그하여 트랜스크립트를 열어야 합니다.


HINT Transcript에 데이터를 기록하는 작업은 Transcript창이 열렸을 때 더 느려집니다. 따라서, 여러분이 Transcript 에 데이터게 기록되는게 느리다고 느껴진다면, Transcript 창을 닫는 것을 고려해 보십시오.


다른 유용한 전역 변수들

  • Smalltalk는 스몰토크 자신을 포함해서, 모든 전역 변수를 정의하는 SystemDictionary 의 인스턴스 입니다. SystemDictionary라는 딕셔너리의 핵심은 스몰토크 코드에서 전역 오브젝트를 이름짓는 심볼입니다. 아래 예를 보겠습니다.
    Smalltalk at: #Boolean      Boolean
    

    Smalltalk 자체가 전역 변수이므로,
    Smalltalk at: #Smalltalk      a SystemDictionary(lots of globals)}
    

    그리고
    (Smalltalk at: #Smalltalk) == Smalltalk       true
    
  • Sensor는 EventSensor의 인스턴스이며, Squeak으로 들어가는 입력들을 처리합니다. 예를 들면, Sensor keyborad는 키보드에 다음 문자 입력에 응답하며, Sensor mousePoint 는 Point는 현재 마우스 위치를 알려주는 반면에, 만약 왼쪽 쉬프트 키가 눌려 있는 상태인 경우 Sensor leftShiftDown 은 true로 응답됩니다.
  • World 는 화면을 표시하는 PasteUpMorph 클래스의 인스턴스입니다. World bounds 는 전체 화면 공간을 정의하는 직사각형의 정보를 반환하며, 화면의 모든 모프는 World 의 하위모프가 됩니다.
  • ActiveHand는 HandMorph의 현재 인스턴스이며, 커서의 그래픽 표현입니다. ActiveHand의 서브모프는 마우스로 드래그한 모든 것을 잡습니다.
  • Undeclared 는 또다른 딕셔너리입니다 - Undeclared 딕셔너리에는 모든 미리 선언되지 않은 변수들이 포함됩니다. 만약 당신이 선언하지 않은 함수를 참조하는 메서드를 작성하게 된다면, 시스템 브라우저는 대개의 경우 선언되지 않은 함수를 선언하도록 알려줍니다. 하지만, 만약 나중에 해당되는 선언문을 삭제한다면, 코드는 선언문이 지워졌기 때문에, 딕셔너리에는 있지만 실제로는 선언되지 않은 변수들을 참조하는 상황이 됩니다. Undeclared 딕셔너리를 살펴보면 가끔 이상한 동작을 하는경우에 대해 도움을 얻을 수 있는 경우도 있습니다.
  • SystemOrganization 은 SystemOrganizer 클래스의 인스턴스입니다: SystemOrganization은 패키지별로 클래스들의 그룹을 기록합니다. 좀 더 정확하게 말하자면, 이것은 클래스들의 이름을 그룹으로 만들어 분류(categorizes)합니다. 그덕분에 다음과 같은 코드로 결과를 얻을 수 있습니다[2].
    SystemOrganization categoryOfElement: #Magnitude      #'Kernel-Numbers'
    


현재의 실행은 글로벌 변수들의 사용을 엄격히 제한하므로, 인스턴스 변수 또는 클래스 변수를 사용하거나, 글로벌 변수들에 접근하기 위해 클래스 메서드를 제공하는 방법이 더 나은 방법입니다. 실제로, 만약 스퀵이 현재 버전의 스크래치(프로그래밍 언어의 일종:역주)로부터 실행될 것이었다면, 클래스가 아닌 대부분의 글로벌 함수들은 아마도 싱글톤으로 대체할 것입니다.

글로벌 변수를 정의하는 일상적인 방법은, 대문자로 변경되었지만 선언하지 않은 식별자에 대한 할당에, 단지 do it을 실행하는 것입니다. 파서는 그 다음, 여러분을 위해 선언할 글로벌 변수를 제공할 것입니다. 만약 여러분이 프로그램으로 글로벌 변수들을 정의하기 원하신다면, Smalltalk at: #AGlobalName put: nil을 실행할 수 있습니다. 이것을 제거하려면, Smalltalk removeKey: #AGlobalName를 실행합니다.


클래스 변수

때때로, 우리는 모든 클래스의 인스턴스들과 클래스 자체들 사이에 몇 가지 데이터를 공유할 필요가 있습니다. 이 작업은 클래스 변수를 사용하여 수행할 수 있습니다. 클래스 변수라는 용어는 변수의 수명이 클래스의 수명과 같다는 의미를 갖습니다. 그럼에도 불구하고, 이 용어가 담지 못하는 내용은 이 변수들이 그림 5.5에 보이는 것처럼 클래스 자체 뿐만 아니라 클래스의 모든 인스턴스들 사이에서도 공유된다는 것을 포함합니다. 실제로, 클래스 변수 보다 좀 더 나은 이름은 ‘공유 변수’ 일 것입니다. 왜냐하면, 이 이름이 좀 더 명확하게 그 변수의 역할을 설명해주기 때문이며 또한, 변수들이 수정되었을 경우, 사용의 위험성을 사용자에게 경고하기 때문입니다.

그림 5.5: 다양한 변수들에 접근하는 인스턴스와 클래스 메서드


그림 5.5에서, 우리는 rgb와 cachedDepth가 Color의 인스턴스 변수인 것을 알 수 있으며, Color 인스턴스에 유일하게 접근할 수 있는 대상들임을 또한 알 수 있습니다. 우리는 또한 superclass,subclass,methodDic와 다른 것들이 클래스 인스턴스 변수임을 알 수 있습니다. 예컨대, 인스턴스 변수들은 오직 color 클래스에 접근할 수 있습니다.

그러나 우리는 또한 약간 새로운 것을 볼 수 있습니다: ColorNames 와 CachedColormaps는 Color를 위해 정의된 class 변수입니다. 이 변수들의 대문자화는 우리에게 이 변수들이 공유되었다는 힌트를 제공합니다. 사실, Color의 모든 인스턴스들은 이 공유된 변수들에 접근할 수 있을 뿐만 아니라, Color 클래스 자체와 그 클래스의 모든 하위 클래스에도 접근할 수 있습니다. 인스턴스 메서드와 클래스 메서드 둘 모두, 이 공유된 변수들에 접근할 수 있습니다.

클래스 변수는 클래스 정의 템플릿에 선언합니다. 예를 들면, 클래스 색상은 color 생성 속도를 높이기 위해 많은 수의 클래스 변수들을 정의하며, 그 변수의 정의는 아래에 보입니다. (클래스 5.20)


클래스 5.20: Color와 Color의 클래스 변수

Object subclass: #Color
  instanceVariableNames: 'rgb cachedDepth cachedBitPattern'
  classVariableNames: 'Black Blue BlueShift Brown CachedColormaps ColorChart
  ColorNames ComponentMask ComponentMax Cyan DarkGray Gray
  GrayToIndexMap Green GreenShift HalfComponentMask HighLightBitmaps
  IndexedColors LightBlue LightBrown LightCyan LightGray LightGreen
  LightMagenta LightOrange LightRed LightYellow Magenta MaskingMap Orange
  PaleBlue PaleBuff PaleGreen PaleMagenta PaleOrange PalePeach PaleRed
  PaleTan PaleYellow PureBlue PureCyan PureGreen PureMagenta PureRed
  PureYellow RandomStream Red RedShift TranslucentPatterns Transparent
  VeryDarkGray VeryLightGray VeryPaleRed VeryVeryDarkGray
  VeryVeryLightGray White Yellow'
  poolDictionaries: ''
  category: 'Graphics--Primitives'


클래스 변수 ColorNames는 빈번하게 사용되는 색상의 이름을 포함하고 있는 배열입니다. 이 배열은 color의 모든 인스턴스에 의해 공유되며, 그 배열의 서브클래스는 TranslucentColor입니다. 이 배열은 모든 인스턴스와 클래스 메서드들로 부터 접근할 수 있습니다.

ColorNames는 일단 Color class»initializeNames에서 초기화되지만, Color의 인스턴스로부터 접근됩니다. 메서드 Color»name은 color의 이름을 찾기 위해 변수를 사용합니다. 대부분의 color가 이름을 갖고 있지 않기 대문에, 모든 color에 인스턴스 변수 이름을 더하는 것이 적절한 것으로 간주됩니다.


클래스 초기화

클래스 변수의 존재는, 다음과 같은 질문을 떠오르게 합니다: 어떻게 이 변수를 초기화 할까? 이것에 대한 한 가지 해결책은 게으른 초기화(lazy initialization) 입니다. 이 초기화는 실행될 때, 변수가 아직 초기화 되지 않았을 경우, 변수를 초기화 하는 접근자 메서드를 소개함으로써, 수행됩니다. 이 게으른 초기화는 우리가 항상 접근자를 사용하고 클래스 변수를 결코 직접 사용하면 안 된다는 사실을 암시합니다. 이 작업은 더 나아가 접근자 보내기와 초기화 테스트의 부담을 사용자에게 전가합니다. 또한 이 초기화는 실제로 더 이상 공유되지 않기 때문에, 클래스 변수 사용을 거의 틀림없이 무산시킵니다.


메서드 5.21: Color class»colorNames

Color class»colorNames
  ColorNames ifNil: [self initializeNames].
   ColorNames


다른 해결책은, 클래스 메서드 초기화를 재지정하는 것입니다.

메서드 5.22: Color class»initialize

Color class»initialize
  ...
  self initializeNames


만약 여러분이 이 해결책을 채택한다면, 여러분이 초기화 메서드를 정의한 다음 (예를 들어) Color initialize를 수행하여 초기화 메서드를 불러올 필요성을 기억하실 필요가 있습니다. 비록 클래스 측면 초기화 메서드들이 코드가 메모리에 로드 될 때, 자동으로 실행되지만, 그 메서드 들은 브라우저에 처음 타이핑 되거나 컴파일 되거나 또는 수정되거나 다시 컴파일 될 때, 자동으로 실행되지 않습니다.


Pool 변수

pool 변수들은 상속으로 연관되지 않을 수 있는 여러 개의 클래스들 사이에서 공유되는 변수들입니다. pool 변수들은 본래 pool 딕셔너리에 저장되지만, 지금은, 개별 클래스(Sharedpool의 하위 클래스)의 클래스 변수로서 정의되어야만 합니다. 우리가 드릴 조언은 이 변수들을 회피하시라는 것이며, 그 이유는 매우 드물고 특정한 상황들에서만 이 변수들이 필요하기 때문입니다. 이 지면에서 우리의 목표는 여러분이 코드를 읽을 때, 이해하실 수 있도록 Pool 변수를 충분히 설명하는 것입니다.

pool 변수에 접근하는 클래스는 그 클래스 정의에서 반드시 pool을 언급해야 합니다. 예를 들면, 클래스 Text는 그것이 pool 딕셔너리 Textcontansts를 사용하고 있다는 것을 가리키며, 이것은 CR과 LF와 같은 모든 문자 상수를 포함합니다. 이 사전은 예를 들면 캐리지 리턴 문자와 같은 값 Character cr에 묶인 key #CR을 갖고 있습니다.


클래스 5.23: Text 클래스에 있는 Pool 딕셔너리

ArrayedCollection subclass: #Text
  instanceVariableNames: 'string runs'
  classVariableNames: ''
  poolDictionaries: TextConstants
  category: 'Collections--Text'


이는 예를 들어, 명백한 딕셔너리 검색 보다는 변수 구문를 사용하여, 메서드 코드 내용에 있는 딕셔너리의 key들에 접근하기 위해 클래스 Text의 메서드를 허용합니다. 예를 들어, 우리는 다음 메서드를 작성할 수 있습니다.


메서드 5.24: Text»testCR

Text»testCR
   CR == Character cr


다시 말해서, 우리는 여러분에게 pool 변수와 pool 딕셔너리 사용을 피하실 것을 권합니다.


Notes

  1. 첫문자가 대문자인 규칙을 말하는듯 합니다.
  2. 이 부분에 대한건 여기를 보면 아주 쪼금 더 자세한 내용을 볼 수 있다