6.11 접근 제어(Access Control)

6.11 접근 제어(Access Control)

기본 가시성(visibility) 옵션이 부족할 때 접근 제어를 사용할 수 있어요. 클래스 수준과 필드 수준에 적용 가능하고 두 방향을 압니다:

  • 접근 허용(Allowing access): :allow(target) 메타데이터를 사용해 대상에게 주어진 클래스나 필드에 대한 접근을 허용한다.
  • 접근 강제(Forcing access): :access(target) 메타데이터를 사용해 대상이 주어진 클래스나 필드에 대한 접근을 허용하도록 강제한다.

이 문맥에서 타겟(target) 은 다음의 점 경로(dot-path)가 될 수 있어요:

  • 클래스 필드
  • 클래스 또는 abstract 타입
  • 패키지

타겟은 import를 존중하지 않으므로, 정규화된(full qualified) 경로를 사용해야 합니다.

클래스나 abstract 타입이면 접근 수정은 그 타입의 모든 필드로 확장됩니다. 마찬가지로 패키지이면 접근 수정은 그 패키지의 모든 타입으로, 그리고 재귀적으로 그 타입들의 모든 필드로 확장됩니다.

@:allow(Main)
class MyClass {
  static private var foo:Int;
}

class Main {
  static public function main() {
    MyClass.foo;
  }
}

여기서 MyClass.fooMyClass@:allow(Main)으로 주석 처리되어 main 메서드에서 접근할 수 있어요. 이것은 @:allow(Main.main)과도 동작하고, 두 버전 모두 클래스 MyClass 대신 필드 foo에 주석을 붙일 수도 있습니다:

class MyClass {
  @:allow(Main.main)
  static private var foo:Int;
}

class Main {
  static public function main() {
    MyClass.foo;
  }
}

타입을 수정해 이런 접근을 허용할 수 없으면, 접근 메서드가 접근을 강제할 수 있어요:

class MyClass {
  static private var foo:Int;
}

class Main {
  @:access(MyClass.foo)
  static public function main() {
    MyClass.foo;
  }
}

@:access(MyClass.foo) 주석은 main 메서드 안에서 foo 필드의 가시성을 효과적으로 무너뜨립니다.

추가 정보: 메타데이터 선택에 관해 — 접근 제어 언어 기능은 추가적인 언어별 구문 대신 Haxe 메타데이터 구문을 사용합니다. 그 이유는 여러 가지입니다:

  • 추가 구문은 종종 언어 파싱에 복잡성을 더하고 (너무) 많은 키워드를 추가한다.
  • 추가 구문은 언어 사용자의 추가 학습이 필요한 반면, 메타데이터 구문은 이미 알려져 있다.
  • 메타데이터 구문은 이 기능의 확장을 허용할 만큼 유연하다.
  • 메타데이터는 Haxe 매크로로 접근/생성/수정할 수 있다.

물론 메타데이터 구문을 사용하는 주된 단점은 메타데이터 키(@:access 등)나 클래스/패키지 이름을 오타했을 때 오류 보고가 없다는 점입니다. 하지만 이 기능으로 허용되지 않은 private 필드에 접근하려 하면 오류가 나므로 조용한 오류의 가능성은 없습니다.

Haxe 3.1.0 이후인터페이스(interface)에 접근이 허용되면, 그 인터페이스를 구현하는 모든 클래스로 확장됩니다:

class MyClass {
  @:allow(I)
  static private var foo:Int;
}

interface I {}

class Main implements I {
  static public function main() {
    MyClass.foo;
  }
}

부모 클래스에 부여된 접근도 true이며, 그 경우 모든 자식 클래스로 확장됩니다.

추가 정보: 깨진 기능 — 자식 클래스와 구현 클래스로의 접근 확장은 Haxe 3.0에서 동작하도록 되어 있었고 문서에도 그렇게 되어 있었습니다. 이 매뉴얼을 쓰는 동안 이 부분의 접근 제어 구현이 단순히 빠져 있다는 것을 발견했습니다.

출처: Access Control

본문

접근 제어의 두 방향

:allow(target)은 대상에게 접근을 허용하고, :access(target)은 대상이 접근하도록 강제해요. 타겟은 클래스 필드, 클래스/abstract, 패키지의 점 경로일 수 있고 import는 존중하지 않아 정규화 경로가 필요합니다.

확장 규칙

클래스/abstract에 대한 접근은 그 모든 필드로, 패키지에 대한 접근은 그 안의 모든 타입(그리고 재귀적으로 필드)로 확장됩니다. 인터페이스에 대한 접근은 구현 클래스로, 부모 클래스에 대한 접근은 자식 클래스로 확장됩니다.

예시

@:allow(Main)을 클래스에, @:allow(Main.main)을 필드에 붙여 private 접근을 허용할 수 있어요. 타입을 수정할 수 없으면 @:access(MyClass.foo)로 강제합니다.

더 알아보기