はじめに
オブジェクト指向プログラミング(OOP)を学び始めると、必ず出てくる概念のひとつがカプセル化です。
「なんとなく聞いたことはあるけど、実際のコードでどう使えばいいの?」という方に向けて、Rubyのコードを使いながら解説していきます。
カプセル化とは
カプセル化とは、データ(変数)と、そのデータを操作する処理(メソッド)をひとまとめにして、外部から直接触れないようにするという考え方です。
薬のカプセルをイメージするとわかりやすいです。カプセルの中に薬が入っていますが、外から直接中身を取り出したり書き換えたりはできません。決められた方法(口から飲む)でしか使えないようになっています。
クラス設計でも同じで、「外から直接触っていいもの」と「外から触らせたくないもの」を明確に分けることがカプセル化の本質です。
カプセル化なしのコードを見てみる
まず、カプセル化を意識していないコードを書いてみます。
class BankAccount
def initialize(balance)
@balance = balance
end
end
account = BankAccount.new(1000)
account.instance_variable_set(:@balance, -99999) # 外から直接書き換えられてしまう
instance_variable_set を使えば、インスタンス変数を外部から直接書き換えることができてしまいます。残高がマイナスになっても誰も気づけません。
これが「カプセル化できていない」状態です。
アクセス修飾子でアクセスを制限する
Rubyでは、メソッドに対して以下の3種類のアクセス修飾子を指定できます。
| 修飾子 | 説明 |
|---|---|
public |
どこからでも呼び出せる(デフォルト) |
private |
クラスの内部からしか呼び出せない |
protected |
同じクラスまたはサブクラスから呼び出せる |
基本的によく使うのは public と private です。
カプセル化を意識したクラス設計
先ほどの銀行口座クラスをカプセル化を意識して書き直してみます。
class BankAccount
def initialize(balance)
@balance = balance
end
# 残高確認(外から見てOK)
def balance
@balance
end
# 入金(外から操作するための窓口)
def deposit(amount)
if amount <= 0
puts "入金額は1円以上にしてください"
return
end
@balance += amount
end
# 出金(外から操作するための窓口)
def withdraw(amount)
if amount <= 0
puts "出金額は1円以上にしてください"
return
end
if amount > @balance
puts "残高が不足しています"
return
end
@balance -= amount
end
private
# 残高を直接書き換えるメソッドは外から触らせない
def set_balance(amount)
@balance = amount
end
end
account = BankAccount.new(1000)
account.deposit(500)
puts account.balance # => 1500
account.withdraw(2000) # => 残高が不足しています
puts account.balance # => 1500
account.set_balance(0) # => NoMethodError: private method 'set_balance' called
set_balance を private にすることで、外部から直接残高を書き換えることができなくなりました。残高を変更したい場合は、必ず deposit や withdraw という「窓口」を通す必要があります。
カプセル化のメリット
不正なデータが入り込まない
deposit や withdraw の中でバリデーション(チェック処理)を行っているため、マイナスの金額や残高以上の出金を防ぐことができます。外から直接 @balance を書き換えることはできないので、データの整合性が保たれます。
内部の変更が外に影響しない
たとえば、残高の計算ロジックを変更したくなったとき、private メソッドの中だけ変更すれば済みます。外部のコードは deposit や withdraw という窓口しか知らないので、内部の実装がどう変わっても影響を受けません。
コードが読みやすくなる
外から使う人は public メソッドだけ把握すればよくなります。「このクラスに何ができるか」が明確になり、コードを読む負担が減ります。
どこを public にして、どこを private にするか
クラス設計でカプセル化を意識するときの判断基準はシンプルで、外から使ってほしいメソッドだけを public にするというものです。
- 外部のコードから呼び出す必要があるメソッド →
public - クラスの内部処理のために使うだけのメソッド →
private
迷ったときは「このメソッド、クラスの外から呼ばれることある?」と考えてみてください。答えがNoなら private にしておくのが無難です。
まとめ
カプセル化とは、データと処理をひとまとめにしながら、外部から直接触れる範囲を制限する考え方です。Rubyでは private キーワードを使うことで、クラスの内部だけで使うメソッドを隠すことができます。
クラス設計でカプセル化を意識することで、「意図しない使われ方を防ぐ」「内部の変更が外に影響しにくくなる」というメリットが得られます。
OOPを学び始めたばかりの段階では、まず「外から触っていいものと触らせたくないものを分ける」という意識を持つだけでも、コードの設計が変わってくると思います。今後もOOPの概念を少しずつ深掘りしていきたいと思います。