Menu
Coddy logo textTech

アクセス制御

CoddyのSwiftジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 17/57。

カプセル化とは、型がそのデータの使用方法を制御することです。アクセス制御によって、プロパティやメソッドを誰が参照できるかが決まります。メンバーに private を付けると、その型の外部にあるすべてのコード(および同じファイル内のその拡張)から隠されます。

struct Account {
    private var balance = 0

    mutating func deposit(_ amount: Int) {
        balance += amount
    }
}

var a = Account()
a.deposit(50)
// a.balance = 1_000_000   // エラー: 'balance' は 'private' 保護レベルのためアクセスできません

コードの外側では、型が提供するものだけを使用できます。型はすべての変更をチェックできるため、そのデータが型で許可されていない状態になることはありません:

struct Account {
    private var balance = 0

    mutating func deposit(_ amount: Int) {
        if amount > 0 { balance += amount }
    }

    func report() -> String {
        "balance: \(balance)"
    }
}

var a = Account()
a.deposit(50)
a.deposit(-999)
print(a.report())

出力:

balance: 50

Swiftには5つのアクセスレベルがあります。キーワードを指定しない場合、メンバーはinternalです。同じモジュール(アプリまたはパッケージ)内のどこからでも見えることを意味します。最も公開範囲が広いものから最も制限の厳しいものまでのレベルは次のとおりです:

open        // 他のモジュールが使用およびサブクラス化できる(クラスのみ)
public      // 他のモジュールが使用できる
internal    // デフォルト: モジュール全体
fileprivate // このソースファイルのみ
private     // この型(およびファイル内のその拡張)

プライベートなヘルパーメソッドによって公開インターフェースを小さく保てます。呼び出し側から見えるのは、その型が何をするかであり、どのように実行するかではありません。

struct Password {
    private let text: String

    init(_ text: String) { self.text = text }

    var isStrong: Bool {
        hasDigit() && text.count >= 8
    }

    private func hasDigit() -> Bool {
        text.contains { $0.isNumber }
    }
}

print(Password("secret123").isStrong)
print(Password("short1").isStrong)

出力:

true
false
challenge icon

チャレンジ

簡単

構造体 Locker を完成させてください。その code と items は private です。store(_:code:) はコードが一致した場合にのみアイテムを追加し、追加できたかどうかを返します。items(code:) はコードが一致した場合、保存されたアイテムを , で結合して返し(または empty を返し)、それ以外の場合は wrong code を返します。

提供されたコードはロッカーのコードを読み込み、その後 put <code> <item> または open <code> のコマンドを処理します。各 put に対して stored または denied を出力し、各 open に対して結果を出力します。

コードは Locker.swift に記述してください。main.swift には提供された入力/出力コードが含まれており、編集できません。

自分で試してみよう

// 提供された入出力コード: そのままにしておく
var input: [String] = []
while let line = readLine() { input.append(line) }
var locker = Locker(code: input[0])
for cmd in input.dropFirst() {
    let p = cmd.split(separator: " ").map(String.init)
    if p[0] == "put" {
        print(locker.store(p[2], code: p[1]) ? "stored" : "denied")
    } else {
        print(locker.items(code: p[1]))
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Swiftプレイグラウンド