접근제어란?

객체지향 프로그래밍 패러다임에서 캡슐화와 은닉화는 중요한 개념 중 하나이다. 은닉화를 구현하기 위한 핵심 기능이 바로 접근제어이다. 접근제어는 코드끼리 상호작용을 할 때 파일 간 또는 모듈 간에 접근을 제한할 수 있는 기능이다.

가령 내가 정의한 코드를 다른 프로그래머가 접근하려할 때 접근제어를 통해 프로그래머에게 제공하고 싶은부분만 노출할 수 있으며 코드작성자의 의도대로 다른 프로그래머가 사용할 수 있도록 유도할 수있다.

Swift에서 명시할 수 있는 접근제어 키워드는 open, public, internal, fileprivate, private 이 있다. 각 타입(class, struct, enum), 타입 내부의 프로퍼티, 메서드, 이니셜라이저, 서브스크립트에 접근수준을 지정할 수 있다. enum에서 case의 접근수준은 enum의 접근수준을 따른다.


접근수준

접근수준 키워드 범위 비고
개방 접근수준 open 모듈외부까지 클레스에서만 사용
공개 접근수준 public 모듈 외부까지  
내부 접근수준 internal 모듈 내부  
파일외부비공개 fileprivate 테스트2 파일 내부  
비공개 접근수준 private 기능 정의 내부  


public - 공개 접근수준

public 키워드는 모듈 내부, 모듈 내부, 파일, 기능단위 등 전 범위에서 사용이 가능하며 Swift의 기본 접근제어 수준은 public이다.

///공개수준으로 정의 되어있는 Fruit구조체 타입
public struct Fruit {
    private var fruitName: String
    private var fruitAmount: Int

    init(name: String, amount: Int) {
        self.fruitName = name
        self.fruitAmount = amount
    }
}


open - 개방 접근수준

open 키워드의 가장 큰 특징은 class와 그 멤버에게만 지정할 수 있다는 것이다. 공개 접근 수준과 차이점이 있다.

  • 개방 접근수준의 클래스는 클래스가 정의된 모듈 밖에서도 상속을 받을 수 있지만 공개수준은 모듈 내부에서만 가능하다

  • 개방 접근수준의 클래스는 클래스내의 멤버수정을 클래스가 정의된 보듈 밖에서도 할 수 있지만 공개수준은 모듈 내부에서만 가능하다.

개방 접근수준으로 클래스를 정의하는 것은 다른 모듈에서도 해당 클래스를 사용하겠다는 목적으로 작성했음을 의미한다.

///개방수준으로 정의 되어있는 Fruit구조체 타입
open class Fruit {
    private var fruitName: String
    private var fruitAmount: Int

    init(name: String, amount: Int) {
        self.fruitName = name
        self.fruitAmount = amount
    }
}


internal - 내부 접근수준

internal은 기본적으로 모든 요소에 암묵적으로 지정하는 기본 접근수준이다. 내부 접근수준으로 지정된 요소가 포함된 소스코드가 포함되는 모듈에서는 접근할 수 있다. 보통 외부 모듈에서 사용하지 않고 내부에서 광역적으로 사용할 때 지정한다.


fileprivate - 파일외부비공개 접근수준

fileprivate은 지정된 요소가 포함된 소스코드 파일 내에서만 접근할 수 잇다.


private - 비공개 접근수준

private으로 지정된 요소는 해당 요소가 포함된 범위에서만 사용가능하다. 같은 파일내부에서도 접근을 할 수 없다.
타입내의 프로퍼티는 항상 private으로 먼저 고려하는게 객체지향적으로 코드를 작성하는 방법이다.


읽기전용 구현

프로퍼티를 정의하면 저장 프로퍼티는 지정된 접근제한 범위 내에서 접근할 수 있다. 그렇다면 해당 프로퍼티에 대해서 접근은 가능하지만 해당 값을 변경할 수 없게 하려면 어떻게 해야할까?

설정자(setter)만 접근 수준을 갖도록 제한할 수 있다. 접근수준(set)으로 표현한다면 해당 프로퍼티에 대하여 설정자의 접근 수준만 낮도록 지정할 수 잇다. 읽기전용(설정자 접근수준 제한)은 서브스크립트, 변수등에 적용될 수 있으며 해당 요소의 접근 수준보다 같거나 낮게 해야한다.

public struct Fruit {
    private var fruitName: String
    
    public var fruitAmount: Int

    public private(set) var fruitColor: String

    init(name: Stirng, amount: Int, color: String) {
        self.fruitName = name
        self.fruitAmount = amount
        self.fruitColor = color
    }
}
//생성자를 통한 접근은 접근자, 설정자 모두 가능하다
var apple = Fruit(name: "사과", amount:10, color: "빨강") 

// 오류발생, private이므로 접근자에 접근이 불가능하므로 설정자또한 불가능
apple.fruitName 

// 10 출력 성공
print(apple.fruitAmount) 

//설정자에 접근하여 값 수정 성공
apple.fruitAmount = 20 

// "red" 출력 성공
print(apple.fruitColor) 

// 오류발생 설정자의 접근제한이 private이므로 수정 불가능
apple.fruitColor = "blue" 


get, set을 이용한 읽기전용 구현

get,set을 사용할때는 저장 프로퍼티와 연산프로퍼티를 따로 정의해주어야한다. 이부분에 대해서는 나중에 자세히 다루겠다. 선언 방식만 보자면

private var count: Int =0

internal private(set) var calculatedcount: Int {
    get {
        return count
    }

    set {
        count +=1
    }
}

get은 접근자 set은 설정자이다. 위의 경우는 set은 private이므로 선언된 범위 외부에서 접근이 불가능하지만 접근자인 get은 internal이므로 해당 파일이 포함된 모듈에서 모두 접근가능하다.




이상 포스팅을 마치겠습니다.🙈