🔖

オブジェクト指向(OOP)を解説してみる

2023/11/29に公開2

1. はじめに

こんにちは、バックエンド ディビジョン所属の藤井です。

この記事では、オブジェクト指向(object-oriented programming, OOP) の基本的な概念を解説します。OOP は、現代のソフトウェア開発において非常に重要な役割を果たしており、多くのプログラミング言語で採用されています。

オブジェクト指向の基本的な要素である 「カプセル化」「ポリモーフィズム」「インターフェース」「継承」 などについて、具体的な例を交えながら解説していきます。また、プログラミングパラダイム の概要についても触れ、プログラミングの多様なアプローチを理解していこうと思います。

このブログを通じて、プログラミングの基本を理解し、オブジェクト指向の第一歩を踏み出すことができれば幸いです。

2. オブジェクト指向(OOP)とは

オブジェクト指向(OOP) は、データとそれに関連するメソッドを 「クラス」という単位でまとめて管理する開発手法です。このアプローチにより、開発者は複雑な機能も再利用可能なモジュールとして効率的に構築できます。例えば、新しい機能を開発する際、既存のクラスから必要なデータを取得し、必要に応じて新しい機能を追加することが可能です。

OOPは1950年代にアラン・ケイ氏によって提唱され、特にプログラミングの複雑さに対応する手段として考案されました。OOPのアイデアを初めて広く実装したプログラミング言語の一つがSmalltalk です。Smalltalkは、オブジェクト指向の概念を具体化し、その後の多くのプログラミング言語に影響を与えました。この方法は、物事の関連性や共通性に基づいてシステムを構築することに焦点を当てています。これは、手続き型プログラミングとは異なり、手続き型はより順序立ててプログラムを記述する手法であると言えます。

3. プログラミング パラダイム

プログラミングパラダイム は、プログラミングの方法論やスタイルを定義する枠組みです。異なるパラダイムは、プログラミングのアプローチや考え方に影響を与え、それぞれが独自の特徴を持っています。

  • 命令型プログラミング

    • 特徴 : 一連の命令文の繰り返しにより変数の値(=状態)を動的に変化させ、計算を行う手法です。データ構造の構築とそれに対する計算のためのアルゴリズムを記述します​​。
    • 利点 : 命令型プログラミングの主な利点は、手順を順番に記述するだけでプログラミングが可能であるため、実装が比較的簡単になることです​​。
    • : C言語、Java、Python など。
  • 宣言型プログラミング

    • 特徴 : 「何をするか」を宣言し、その「方法」は指定しません。地図で目的地を指定するが、どの道を通るかは指定しないようなものです。
    • 利点 : 宣言型プログラミングは、プログラムが何をするかを簡単に記述することで、複雑な処理や計算をシンプルに扱えるようにし、プログラムの速度と効率を向上させる利点があります。
    • : SQL など。
  • オブジェクト指向プログラミング

    • 特徴 : データと機能をオブジェクトとして組み合わせます。人間の社会で、個々の人が特定の役割と責任を持つようなものです。
    • 利点 : プログラムの各部分を明確に区別し、複数人での開発がしやすくなります。また、問題の特定や修正がしやすく、大規模なプロジェクトや長期的なメンテナンスに適しています。
    • : Java、PHP、Ruby、JavaScript、Python など。
  • 関数型プログラミング

    • 特徴 : 関数型プログラミングでは、プログラムを一連の関数の組み合わせとして扱います。このアプローチでは、同じ入力に対して常に同じ結果を返す「純粋関数」が中心となります。
    • 利点 : 副作用が少なく、テストやデバッグが容易になります。また、並行処理や大規模なデータの操作に強く、複雑なシステムでも予測可能で安定した動作を提供します。
    • : Haskell、Scala、Erlang など。
  • 論理型プログラミング

    • 特徴 : 論理式を用いて問題を解決します。パズルを解くように、事実と規則から答えを導き出します。
    • 利点 : 数学や哲学の論理的なアプローチを取り入れたもので、問題解決の過程が明確で、信頼性の高い方法を提供します。特に人工知能の分野での応用に影響を与えています​​。
    • : Prolog、並行論理プログラミング、制約論理プログラミング、仮説論理プログラミング など。
  • 構造化プログラミング

    • 特徴 : 単純な制御構造を用いてプログラムを構築します。建物の設計図を作るように、プログラムを階層的に整理します。
    • 利点 : 構造化プログラミングは、プログラムの流れや構造が理解しやすく、プログラムの正当性や検証を容易にします。
    • : C言語、Pascal など。
  • 制約プログラミング

    • 特徴 : 制約条件を宣言し、それらを満たす解を見つけます。パズルのピースを適切な場所にはめ込むようなものです。
    • 利点 : 複雑な問題解決に適しています。
    • : Prolog、MiniZinc など。

まとめ

これらの プログラミングパラダイム は、プログラマーが適切なアプローチを選択し、効果的にプログラムを設計するのに役立ちます。オブジェクト指向プログラミングは、これらの中でも特に大規模なシステムの開発において重要な役割を果たしています。

4. カプセル化

オブジェクト指向プログラミングにおける 「カプセル化」 は、クラス内のデータ(属性)とメソッド(操作)を外部からの直接的なアクセスから保護する概念です。これは、重要な情報を安全な場所に保管し、限られた方法でのみアクセスを許可する金庫に似ています。

alt

カプセル化の特徴

  • データの隠蔽 : クラス内のデータは外部から直接アクセスされないように隠蔽されます。これにより、データの安全性と整合性が保たれます。

  • メソッドを介したアクセス : 外部からデータにアクセスするには、クラスが提供するメソッドを通じて行います。これにより、データの使用方法を制御し、不適切なアクセスを防ぎます。

  • アクセス修飾子の使用 : private, public などのアクセス修飾子を使用して、データとメソッドのアクセスレベルを定義します。通常、データは private 修飾子を用いて隠蔽され、メソッドは public 修飾子を用いて外部からアクセス可能にされます。

カプセル化の例

銀行口座のクラスを考えてみましょう。このクラスには、口座残高(データ)と、お金を預ける/引き出す(メソッド)があります。口座残高は外部から直接アクセスできないように private として隠蔽され、お金を預ける/引き出す操作は public メソッドを通じて行います。これにより、不正な方法で口座残高を変更することが防がれ、口座の安全性が保たれます。

まとめ

カプセル化 は、クラスのデータを外部からの直接的なアクセスから保護し、メソッドを通じてのみアクセスを許可することで、データの安全性と整合性を保つ重要な概念です。金庫に重要な物を保管するように、カプセル化はプログラム内の重要なデータを安全に保ち、適切な方法でのみアクセスを許可します。

5. ポリモーフィズム

オブジェクト指向プログラミングにおける 「ポリモーフィズム」 は、異なるクラスのオブジェクトが同じインターフェースやメソッドを共有し、それぞれ異なる方法でこれらを実装することを指します。ポリモーフィズムは日本語で 「多様性」「多態性」「多相性」 と訳され、多様な形や状態をとることができることを意味します。

ポリモーフィズムの特徴

  • 統一されたインターフェース : 異なるクラスのオブジェクトが同じメソッド名を共有しますが、その実装はクラスごとに異なります。

  • 柔軟なコード : 同じメソッド名で異なる動作をすることにより、コードが柔軟になり、新しいクラスの追加や変更が容易になります。

  • 簡潔で読みやすいコード : 異なるオブジェクトでも共通のメソッドを使用するため、コードが簡潔で読みやすくなります。

ポリモーフィズムの例

犬、猫、電気ネズミのクラスを想像してみましょう。これらのクラスには共通のメソッド「鳴く」がありますが、犬クラスの「鳴く」メソッドは「ワン」という音を出し、猫クラスは「ニャー」、電気ネズミクラスは「ピッカッ」という音を出します。

プログラム内で、これらの異なるオブジェクトを同じ型(例えば、動物型)の変数に代入し、ループ内で各オブジェクトの「鳴く」メソッドを呼び出すと、それぞれのオブジェクト固有の鳴き声が出力されます。これにより、異なるオブジェクトでも同じメソッド名で異なる動作を実現し、コードの柔軟性と読みやすさが向上します。

alt

まとめ

ポリモーフィズム は、異なるクラスのオブジェクトが同じインターフェースやメソッドを共有しながら、それぞれ独自の方法でこれらを実装することを可能にします。これにより、プログラムはより柔軟で、変更に対しても強く、コードの簡潔さと読みやすさが向上します。まるで異なる楽器が同じ曲を演奏するように、異なるクラスのオブジェクトが同じメソッドを使って独自の動作をします。

6. カプセル化とポリモーフィズムの違い

ここまでカプセル化ポリモーフィズム を解説してきましたが、これらは、オブジェクト指向プログラミングの重要な概念です。おさらいを兼ねて重要な違いがあるということを解説しておきます。

カプセル化

オブジェクト指向プログラミングにおいて、カプセル化はデータとメソッドの隠蔽に重点を置きます。これは、内部構造やデータを外部から隠し、プログラムの安全性を保つための手法です​​。

ポリモーフィズム

ポリモーフィズムは「多様性」を意味し、異なるオブジェクトが同じような役割や機能を持ちながらも、それぞれ異なる実装や動作をすることを可能にします。たとえば先ほども例に挙げていた、様々な動物が「鳴く」という共通の行動を持つが、犬、猫などはそれぞれ独自の鳴き声を出すような場合です。

なぜ理解することが重要か

カプセル化ポリモーフィズム は、共にオブジェクト指向プログラミングの重要な要素ですが、それぞれ異なる目的を持っています。カプセル化は安全性を高めるためにデータの隠蔽に焦点を当て、ポリモーフィズムはコードの柔軟性と再利用性を高めるために異なるオブジェクトが似た役割や機能を持つことに注目しています。これらの違いを理解し、適切に使用することが効率的で安全なソフトウェア開発に必要です。

7. 継承

オブジェクト指向プログラミングにおける 「継承」 は、あるクラス(親クラス)の特性や機能を新しいクラス(子クラス)が引き継ぐ仕組みです。これは、親から子へ特性や財産が受け継がれる家族の関係に似ています。

継承の特徴

  • 特性の引き継ぎ : 子クラスは親クラスの特性(プロパティ)や機能(メソッド)を自動的に受け継ぎます。例えば、あなたが親から髪の色や目の色を受け継ぐように、子クラスも親クラスの特性を受け継ぎます。

  • 新たな特性の追加 : 子クラスは親クラスの特性に加えて、新しい特性や機能を持つことができます。これは、あなたが親の特性を受け継ぎつつ、独自の才能やスキルを持つことに似ています。

  • コードの再利用 : 既存のクラスのコードを再利用して、新しいクラスを作ることができます。これにより、コードの重複が減り、プログラムの保守や拡張が容易になります。

継承の例

「is-a」の関係を考えてみましょう。
例えば、RPGのキャラクターで、「ウィザード( Wizard )」は「キャラクター ( Character )」という親クラスの特性を継承します。キャラクターには、体力ポイント、攻撃力、防御する、攻撃するなどの基本的な特性があります。ウィザードはこれらの基本特性を受け継ぎつつ、独自の特性として魔法を使用し、呪文を唱えることができます。

同様に、「戦士 ( Warrior )」も「キャラクター ( Character )」という親クラスの基本特性を受け継ぎつつ、強力な攻撃を行い、盾を使用することができます。そして、「アーチャー( Archer )」も「キャラクター ( Character )」の基本特性を持ち、弓を使用して、正確なショットも放つことが得意です。

このように、各キャラクターは親クラスから基本特性を継承しつつ、独自の特性を持っています。

alt

継承の利点

  • 効率的な新クラスの作成 : 既存のクラスの特性を再利用することで、新しいクラスを効率的に作成できます。

  • コードの整理 : 共通の特性を親クラスにまとめることで、コードが整理され、読みやすくなります。

  • 拡張の容易さ : 新しい特性や機能を追加する際に、既存のコードを変更する必要が少なくなります。

まとめ

継承 は、親クラスの特性を子クラスが引き継ぐことで、効率的に新しいクラスを作成し、コードの再利用性を高める強力なツールです。家族で特性が受け継がれるように、プログラミングでもクラス間で特性が受け継がれ、新しいクラスがより簡単に、そして効率的に作られます。

8. インターフェース

オブジェクト指向プログラミングにおける 「インターフェース」 は、異なるクラス間の通信のルールを定める契約のようなものです。これは、異なる機器間の接続を可能にする電子機器のインターフェースに似ています。たとえば、USBポートは様々なデバイスとパソコンを接続するための共通のインターフェースです。

インターフェースの特徴

  • 機能の定義 : インターフェースは、特定の機能やプロトコルを定義しますが、その具体的な実装は含みません。これは、USBポートが「データを送受信する」という機能を定義しているが、どのようにデータを処理するか(例えば、写真を転送するか、ドキュメントを転送するか)は定めていないのに似ています。

  • 異なるクラス間の通信 : インターフェースを通じて、異なるクラスが共通の言語で通信できます。例えば、PCクラスとMouseクラスがある場合、PCクラスはMouseクラスの詳細を知らなくても、インターフェースで定義された方法でマウスを操作できます。

  • 柔軟性と拡張性の向上 : インターフェースを使用することで、システムの一部を変更または拡張しても、他の部分に影響を与えにくくなります。USBポートを使えば、さまざまな種類のデバイスを接続できるように、インターフェースを使うことで、新しいクラスや機能を容易に追加できます。

インターフェースの例

パソコンとマウスの関係を考えてみましょう。パソコン(PCクラス)は、マウス(Mouseクラス)を使って操作されます。ここで、パソコンはマウスの詳細(マウスがどのように動くか、どのボタンがどの機能を持つかなど)を知る必要はありません。パソコンとマウスは「マウスインターフェース」という共通の規約を通じて通信します。このインターフェースは、マウスの動きやボタンのクリックをパソコンが理解できる形に変換します。

インターフェースと抽象クラスの違い

ここで、インターフェースは、抽象クラス という概念と似ているのですが、混合しやすいため、いくつかの重要な違いがあるということを解説しておきます。

抽象クラス

  • 抽象クラスの概念と役割 : 抽象クラスは、インスタンス化できないクラスで、1つ以上の抽象メソッド(実装がないメソッド)を持ちます。抽象クラスは、サブクラスで具体的な実装を行うための「骨組み」を提供します。

インターフェースとの違い

  • メソッドの実装 : 抽象クラスは抽象メソッドと非抽象メソッドの両方を含めることができますが、インターフェースは基本的に抽象メソッドのみを持ちます。

  • 変数の種類 : 抽象クラスは、変更可能または変更不可能、クラス共通または個々のインスタンスごとに特有な、さまざまな種類の変数を持つことができます。対して、インターフェースは、基本的には、クラス全体で共通かつ変更できない変数のみを持つことができます。

  • 継承と実装 : 抽象クラスは、他のクラスの基本的な特徴や機能を「受け継ぐ」ために使用されます。ただし、一度に一つのクラスからのみ特徴を受け継ぐことができます。対して、インターフェースは、複数の異なるクラスが共通の「規則や機能」を持つために使用されます。一つのクラスが複数の異なる規則や機能を同時に持つことが可能です。

まとめ

インターフェース は、異なるクラスやシステム間での通信のルールを定める重要な概念です。これにより、システムの異なる部分が効果的に連携し、柔軟性と拡張性を持って動作することができます。USBポートがさまざまなデバイスとの接続を可能にするように、プログラミングのインターフェースは異なるクラス間のスムーズな連携を実現します。

9. 合成(コンポジション)

オブジェクト指向プログラミングにおける 「合成(コンポジション)」 は、複数の小さな部品(オブジェクト)を組み合わせて、一つの大きな機能を持つオブジェクトを作る方法です。これは、まるでレゴブロックを組み合わせて大きな城やロボットを作るようなものです。各レゴブロックが小さな部品で、それらを組み合わせることで、一つの大きな作品が完成します。

合成の特徴

  • 強い関連性 : 合成では、小さな部品は大きなオブジェクトの重要な一部となります。例えば、車を考えてみましょう。車はエンジン、タイヤ、窓などの部品で構成されています。これらの部品は車という全体の機能に不可欠です。

  • ライフサイクルの共有 : 車の例で言えば、車が廃車になると、エンジンやタイヤも通常は使用されなくなります。つまり、全体(車)の寿命が部品の寿命に影響を与えます。

  • 再利用性の向上 : 合成を使うと、既にある部品(例えば、タイヤ)を異なる車種で再利用できます。これにより、新しい車を設計する際の時間とコストが節約できます。

合成の利点

  • 疎結合 : 各部品は独立しているため、一部を変更しても他の部分に大きな影響を与えません。例えば、車のラジオを交換しても、エンジンには影響しません。

  • 拡張性 : 新しい機能を追加する際に、既存の部品を再利用しやすいです。新しいタイプのタイヤを開発したら、それを様々な車に適用できます。

  • 保守性 : 部品ごとにメンテナンスや修理ができるため、全体の修理よりも簡単でコストが低くなります。タイヤがパンクしたら、そのタイヤだけを交換すればいいわけです。

まとめ

合成 は、小さな部品を組み合わせて大きなシステムを作る強力な方法です。レゴブロックを使って色々なものを作るように、プログラミングでも小さな部品(オブジェクト)を組み合わせて、大きく複雑なプログラムを作ります。これにより、プログラムは理解しやすく、修正や拡張がしやすくなります。

10. おわりに

この記事を最後まで読んでいただき、ありがとうございます。

今回、オブジェクト指向(OOP) の基本的な概念について掘り下げてきました。カプセル化、ポリモーフィズム、インターフェース、継承、さまざまなプログラミングパラダイムなどについて紹介しました。これらの概念は、現代のソフトウェア開発において非常に重要であり、多くのプログラミング言語で採用されています。

最後に、もし何か質問やフィードバックがあれば、ぜひコメント欄にてお知らせください。
ご一読いただき、ありがとうございました。

Discussion

sumimsumim

> OOPは1950年代にアラン・ケイ氏によって提唱

正しくは、1960年代(1966年頃)ですね^^;

あと、このときの氏の発想は、ご説明の抽象データ型ベースの「オブジェクト指向」とはだいぶ方向性が異なるものなので、もしご興味をお持ちでしたら bit.ly/totencja や、着想の経緯まで詳しく書かれた bit.ly/earlyhst などを読んでみてください!

クラウドエース株式会社クラウドエース株式会社

執筆者の藤井です。
コメントありがとうございます。貴重なご指摘をいただき、感謝いたします。
ご指摘の通り、オブジェクト指向プログラミング(OOP)の概念は、1960年代にアラン・ケイ氏によって初めて提唱されました。私の記事で1950年代と記載したのは誤りでした。
また、アラン・ケイ氏の初期の考え方と、後に定着したオブジェクト指向のアプローチには、確かに違いがあります。私の記事ではその違いに十分な説明を加えていませんでした。
ご紹介いただいたリンクには、この点についての詳しい情報が含まれているようですので、私自身も学びを深めたいと思います。