オブジェクト指向のカプセル化について今日は紹介するよ!
- オブジェクト指向のカプセル化ってなに?
- オブジェクト指向のカプセル化は何のためにあるの?
- 説明だけだとわからないからコードで書きたい
などの疑問をお持ちの方の悩みを解決できる記事になっています!
オブジェクト指向は初心者の人にとって難しいかもしれません。色々なサイトで見たけど、よくわからなかったという人も多いのではないでしょうか。
オブジェクト指向の重要な概念で、次のようなものがあります。
- クラス
- カプセル化
- 継承
- ポリモーフィズム
オブジェクト指向を習得するためには、これらの理解が必要です。オブジェクト指向が扱う範囲は広いです。そのため、基本をしっかりと抑えておかないと、挫折してしまうかもしれません。
この記事では、オブジェクト指向のカプセル化、カプセル化の目的、カプセル化の使い方などを完全初心者向けに解説します!
サンプルのコードをあわせて説明しますので、実際にコードを書いて動作確認してみましょう!
記事を読めば、オブジェクト指向のクラスについて理解ができますよ!
- オブジェクト指向のカプセル化の使い方を知りたい人
- オブジェクト指向のカプセル化をコードで書けるようになりたい人
- オブジェクト指向を一言で説明できない人
オブジェクト指向のカプセル化を学ぶ前に
オブジェクト指向のカプセル化を学習する前に注意してほしいことがあります。
オブジェクト指向のカプセル化を理解するために、実際にコードを書いて動作確認をしてください。
なぜなら、コードを書かずに頭だけで理解することは難しいからです。
サンプルコードを書いて動作確認することを「写経」といいます。
写経することで、カプセル化の書き方や、なぜ動くのかを確認することができます。初心者の頃は横着してコピペする人が多いですが、これは非常にもったいないです。
手を動かして書くことで、記憶の定着が上がり、コードを書くことに慣れます。
実際に、プロのエンジニアも新しいプログラミング言語を習うときは、写経する人が多いです。
写経することで、頭の整理がしやすいからですね。
それに、体で覚える感覚を養うことができます。
私も写経は必ずやります。
オブジェクト指向をしっかり理解したい人は、サンプルコードを書くようにしてくださいね。
それでは、見てみましょう!
Rubyの実行環境
この記事では、カプセル化のサンプルコードは「Ruby」を書きます。
Rubyの実行環境は手元のパソコンでもいいですし、オンライン上でも大丈夫です。
例えば、こちらのサイトならオンライン上でコードを書くことができます。
オブジェクト指向ってなに?
オブジェクト指向とは、システム開発を効率的に行うための総合的な技術を指します。
オブジェクト指向は当初はプログラミング言語として開発されました。「クラス」「継承」「ポリモーフィズム」などの概念を取り入れ、オブジェクト指向プログラミング言語(OOP)と呼ばれるようになりました。
その後、プログラミング以外にもデザインパターンやUML、モデリングなどにも応用され、オブジェクト指向という概念が形成されました。
オブジェクト指向の基本についてこちらの記事で詳しく解説しています。オブジェクト指向のカプセル化を理解するためにも目を通しておきましょう。
【保存版】オブジェクト指向とは?プログラミング初心者向けに解説!オブジェクト指向のクラスとは
クラスとは「種類」「分類」を意味し、「性質が同じものの集まり」です。
Rubyでクラスを書くときは、class
キーワードを使います。
次の例では、車を表すCar
クラスを定義しています。
class Car
def initialize(name, color, model_year)
@name = name
@color = color
@model_year = model_year
end
attr_accessor :name, :color, :model_year
end
インスタンスは、new
を使って次のように書きます。
class Car
def initialize(name, color, model_year)
@name = name
@color = color
@model_year = model_year
end
attr_accessor :name, :color, :model_year
end
# インスタンスをつくる(インスタンス化させる)
toyota = Car.new("TOYOTA", "黒", "20年式")
puts toyota.name
puts toyota.color
puts toyota.model_year
クラスとインスタンスの違いや、クラスの使い方はこちらで解説しているので確認してみましょう。
オブジェクト指向のクラスとは?初心者でもわかる!オブジェクト指向のカプセル化とは
オブジェクト指向のカプセル化とは、「インスタンスのプロパティやメソッド隠蔽してアクセスできる範囲を明確にすること」です。
なぜ、インスタンスのプロパティやメソッドを隠さなければならないのでしょうか。
例えば、車というクラスがあるとします。
車クラスは次のようなプロパティとメソッドをもっています。
クラス | プロパティ | メソッド |
車 |
|
|
これをRubyで表現すると次のようになります。
class Car
def initialize(name, color, model_year)
@name = name #名前
@color = color #色
@model_year = model_year #年代
end
# 年代を返す
def get_model_year
@model_year
end
attr_accessor :name, :color, :model_year
end
ではインスタンスを生成してみましょう。
インスタンスを生成し、車の「年代」を出力してみます。
class Car
def initialize(name, color, model_year)
@name = name #名前
@color = color #色
@model_year = model_year #年代
end
# 年代を返す
def get_model_year
@model_year
end
attr_accessor :name, :color, :model_year
end
# インスタンスを生成する
toyota = Car.new("TOYOTA", "黒", "20年式")
# 年代を出力する
puts toyota.get_model_year
get_model_year
を実行すると次のように「20年式」という結果がかえってきました。
get_model_year
で年代を取得できました。
しかし、get_model_year
を使わなくても年代を取得できる方法がもう一つあります。
それは、プロパティのmodel_year
に直接アクセスして取得する方法です。
インスタンスのmodel_year
にアクセスして年代を出力してみましょう。
class Car
def initialize(name, color, model_year)
@name = name #名前
@color = color #色
@model_year = model_year #年代
end
# 年代を返す
def get_model_year
@model_year
end
attr_accessor :name, :color, :model_year
end
# インスタンスを生成する
toyota = Car.new("TOYOTA", "黒", "20年式")
# 年代を出力する
puts toyota.get_model_year
# プロパティにアクセスして取得する
puts toyota.model_year
実行した結果は次の通りです。同じ値が出力されていますね。
「年代」を取得する方法が二つあることがわかりました。
しかし、これは年代の取得方法が、使う人によって別れてしまうかもしれません。
ある人はプロパティのmodel_year
を使用し、ある人はメソッドのget_model_year
を使用するかもしれません。
このようにバラバラに使われてしまうとクラスの変更がしづらくなります。
なぜなら、変更の影響範囲が大きくなるからです。
例えば、プロパティのmodel_year
を変更すると全てのインスタンスのmodel_year
を変更しなければなりません。100個インスタンスがあったときは、100箇所変更範囲が及びます。
また、仮にこのクラスを作った人がget_model_year
だけ使ってくれると期待して、プロパティのmodel_year
の名前をmodel_year_2
に変更してしまったとします。
すると、インスタンスのmodel_year
をアクセスしてた箇所が一気にエラーになってしまいます。
変更の影響範囲が大きくなるのは、プログラミングでは好ましくありません。影響範囲はなるべく小さくして責任を明確に分けた方がメンテナンス性の高いコードになります。
それを実現するために、カプセル化が使用されます。
カプセル化はプロパティやメソッドを隠蔽して、責任を明確にするものです。
ここでは、プロパティのmodel_year
を隠蔽してget_model_year
だけアクセスできるように変更しましょう。
Rubyでインスタンスのプロパティへのアクセス制御はattr_accessor
で行います。
attr_accessor
で定義した値がインスタンスからアクセスできるので、model_year
をここから消します。
class Car
def initialize(name, color, model_year)
@name = name
@color = color
@model_year = model_year
end
def get_model_year
@model_year
end
# model_yearを消す
attr_accessor :name, :color
end
toyota = Car.new("TOYOTA", "黒", "20年式")
puts toyota.get_model_year
# プロパティにアクセスできない
# puts toyota.model_year
これで、プロパティのmodel_year
は外からアクセスできなくなりました。
こうすることで、get_model_year
だけが「年代」にアクセスできるメソッドとして定義できます。
もしmodel_year
にアクセスしようとすると、コンパイラはエラーを出力します。
カプセル化を使うことで、アクセスできる範囲を明確にできました。
このように、カプセル化はクラス内で公開にしたい項目と公開したくない項目を分けることができます。
なぜ、カプセル化が必要なのか
カプセル化の目的は、「アクセスできる範囲を明確にすること」です。
アクセスできる範囲を明確にすることで得られるメリットは次のようなものがあります。
- 修正の影響範囲を小さくできる
- 変更に強いクラス設計ができる
修正の影響範囲を小さくできる
前述した通り、アクセスできるプロパティやメソッドを絞ることで公開する範囲を制限できます。
範囲を制限できれば、内部のプロパティが変わっても影響範囲を最小限に抑えられます。
例えば、model_year
が公開されてる状態を考えてみましょう。
次のように、複数のインスタンスでmodel_year
を使われているとします。
class Car
def initialize(name, color, model_year)
@name = name
@color = color
@model_year = model_year
end
def get_model_year
@model_year
end
attr_accessor :name, :color, :model_year
end
car1 = Car.new("TOYOTA", "黒", "20年式")
car2 = Car.new("TOYOTA", "赤", "10年式")
car3 = Car.new("TOYOTA", "青", "08年式")
car4 = Car.new("TOYOTA", "グレー", "06年式")
# 複数のインスタンスでmodel_yearが使われている
puts car1.model_year
puts car2.model_year
puts car3.model_year
puts car4.model_year
次に、新しいメソッド「get_name_and_model_year
」を定義します。
class Car
def initialize(name, color, model_year)
@name = name
@color = color
@model_year = model_year
end
def get_model_year
@model_year
end
# 新しいメソッドを定義する
def get_name_and_model_year
@name + @model_year
end
attr_accessor :name, :color, :model_year
end
car1 = Car.new("TOYOTA", "黒", "20年式")
car2 = Car.new("TOYOTA", "赤", "10年式")
car3 = Car.new("TOYOTA", "青", "08年式")
car4 = Car.new("TOYOTA", "グレー", "06年式")
puts car1.model_year
puts car2.model_year
puts car3.model_year
puts car4.model_year
puts car1.get_name_and_model_year
get_name_and_model_year
は「名前 + 年代」を繋げた値を返します。
では、ここでmodel_year
をmodel_year_2
に変更したいとしましょう。
変更を適用すると次のようになります。
class Car
def initialize(name, color, model_year)
@name = name
@color = color
# model_year_2の変更を適用
@model_year_2 = model_year
end
def get_model_year
# model_year_2の変更を適用
@model_year_2
end
def get_name_and_model_year
# model_year_2の変更を適用
@name + @model_year_2
end
# model_year_2の変更を適用
attr_accessor :name, :color, :model_year_2
end
car1 = Car.new("TOYOTA", "黒", "20年式")
car2 = Car.new("TOYOTA", "赤", "10年式")
car3 = Car.new("TOYOTA", "青", "08年式")
car4 = Car.new("TOYOTA", "グレー", "06年式")
# model_year_2の変更を適用
puts car1.model_year_2
puts car2.model_year_2
puts car3.model_year_2
puts car4.model_year_2
puts car1.get_name_and_model_year
クラス内だけでなく、インスタンスの方まで変更範囲が及びましたね。
では、もしget_model_year
を使っていた場合はどうでしょうか。
class Car
def initialize(name, color, model_year)
@name = name
@color = color
# model_year_2の変更を適用
@model_year_2 = model_year
end
def get_model_year
# model_year_2の変更を適用
@model_year_2
end
def get_name_and_model_year
# model_year_2の変更を適用
@name + @model_year_2
end
# model_year_2の変更を適用
attr_accessor :name, :color, :model_year_2
end
car1 = Car.new("TOYOTA", "黒", "20年式")
car2 = Car.new("TOYOTA", "赤", "10年式")
car3 = Car.new("TOYOTA", "青", "08年式")
car4 = Car.new("TOYOTA", "グレー", "06年式")
# model_year_2の変更は影響されない
puts car1.get_model_year
puts car2.get_model_year
puts car3.get_model_year
puts car4.get_model_year
puts car1.get_name_and_model_year
クラス内の影響は変わらずですが、インスタンスからのアクセス箇所は変更されていません。
このように、カプセル化することによってクラス内部の影響を外部に漏らさずに最小限で抑えることができます。
変更に強いクラス設計ができる
カプセル化で影響範囲を最小限に抑えることができるということは、変更に強いクラス設計ができるということにもなります。
オブジェクト指向は「効率的にシステム開発をするために使われる技術」です。
効率的なプログラミングをするためには、変更に強い仕組みを作らなければなりません。
なぜなら、提供するサービスやビジネスは日々進化し、それにともないシステムを変更をしなければならないからです。
システムを柔軟に変更するには、クラス設計が重要になります。
クラスの内部実装は柔軟に変更できるように構築しなければなりません。
そのためにカプセル化という技術が使われるのです。
まとめ
この記事では、オブジェクト指向のカプセル化についてまとめました。
最後にもう一度内容を確認しましょう。
- オブジェクト指向のカプセル化とは「インスタンスのプロパティやメソッド隠蔽してアクセスできる範囲を明確にすること」
- カプセル化でアクセスできる範囲を明確にすると「修正の影響範囲を小さくできる」「変更に強いクラス設計ができる」などのメリットを享受できる
カプセル化と聞くと難しそうに聞こえるかもしれませんが、その目的や必要性を理解できれば理にかなった概念だと気づくでしょう。
いまいちピンとこない人は、実際にコードを書いてみましょう!上記であげたサンプルコードを写経してください。
一つ一つ何をやっているのか確認しながら、書いてください。
なんとなくでも理解できれば今は十分です。
実際の現場で使うことになれば、より実践的な使い方を学べるでしょう。そのときのために頭の片隅に置いておいてください。
オブジェクト指向は難しい概念ですが、基礎を理解し、実践すれば身に付きます!
オブジェクト指向のカプセル化以外にも、クラス、継承、ポリモーフィズムも重要な概念です。
こちらもあわせてしっかり確認しておきましょう!