Upgrade to Pro — share decks privately, control downloads, hide ads and more …

実践オブジェクト指向設計サブ資料:①オブジェクト指向の基礎

Recruit
August 09, 2024

 実践オブジェクト指向設計サブ資料:①オブジェクト指向の基礎

2024年度リクルート エンジニアコース新人研修の講義資料です

Recruit

August 09, 2024
Tweet

More Decks by Recruit

Other Decks in Technology

Transcript

  1. サブ資料①:オブジェクト指向の基礎 オブジェクト指向言語の構成要素:クラス / インスタンス / オブジェクト オブジェクト指向プログラミングにおいて、共通のプロパティとメソッドを持つオブジェクトの設 計図となるもので実際のオブジェクトを生成する際に利用され、メモリの静的データ領域にロード される。 クラス(Class)

    インスタンス(Instance) オブジェクト(Object) オブジェクト指向プログラミングにおいて、データと処理を一体化したもので、クラスから生成された インスタンスのことを指す。一般に、インスタンスとオブジェクトは同義語として使われることが多い 設計図であるクラスから生成され、実際にメモリ(ヒープ領域)上に確保されるオブジェクトを指 す。あるクラスから別々に生成された複数のインスタンスは、それぞれ独立したメモリ領域に格納 される。 オブジェクト指向の考え方 オブジェクト指向は、プログラムの構造を分割し、それぞれのオブジェクトが特定の責任を持つよ うにすることで、複雑な問題を解決する手法で、現実世界の要素や概念をプログラム内のオブジェ クトとして表現することで、プログラムの設計や実装をより理解しやすく、柔軟性のあるシステム の構築を可能にする。 オブジェクト指向では、各オブジェクトがデータと振る舞いを持ち、他のオブジェクトと相互作用 することでシステムが構築される。オブジェクトはそれぞれが独立して存在し、自己の状態を持 ち、他のオブジェクトとメッセージのやり取りを行う。 オブジェクト指向は抽象化、カプセル化、継承、ポリモーフィズムといった概念や原則を用いて、 プログラムをより柔軟に設計することが可能。これにより、コードの再利用性や拡張性が高まり、 大規模なシステムの開発においても効果的な手法となっている。 1 ページ
  2. オブジェクトの基本原則 『オブジェクトは属性(データ)と振る舞い(関数・メソッド)を持つ』 オブジェクト指向プログラミングでは、現実世界の物事や概念をオブジェクトとしてモデル化し、 オブジェクトは、その特性や状態を表す属性(データ)を持ち、それに対して操作や振る舞いを行 うためのメソッドを提供する。 属性はオブジェクトの状態や特徴を表現し、オブジェクトの状態が変化することで属性の値も変化 する。例えば、車のオブジェクトでは、色や速度などが属性となる。 一方、振る舞いはオブジェクトが行う操作や機能を表現する。オブジェクトは他のオブジェクトと の相互作用を通じて振る舞いを実現する。例えば、車のオブジェクトでは、加速や停止といった振 る舞いを持つ

    継承 継承とは、あるクラス(継承元、親クラス、スーパークラス)の特性や振る舞いを別のクラス (継承先、子クラス、サブクラス)が引き継いで利用することを意味する 継承を通じて、既存のクラスを拡張し、共通の特性や振る舞いを再利用することが可能 継承の関係では、「継承先は継承元の一種である(is-a 関係)」といえ、例えば、継承元が「動 物」というクラスであり、継承先が「犬」というクラスであれば、「犬は動物である」と言える なお、Javaでは、単一継承(クラスが1つの親クラスからのみ継承できる)がサポートされてお り、多重継承(1つ以上の親クラスからの継承)は禁止されている。 継承は縦の関係(階層関係)を表し、クラスの階層を形成する。継承元のクラスが継承先のクラスの 基盤となり、継承先は継承元の特性や振る舞いを受け継ぐことができる。これにより、継承先は継承 元の機能を拡張したり、振る舞いを上書きすることが可能。 一方、インターフェースは横の関係(※同じ服を着る、同じグループである等の共通点を持つニュア ンスでの横関係)を表し、クラスが提供する契約(抽象メソッドの宣言)を定義する。インター フェースは実装側がその契約を遵守することで、異なるクラス間で共通の振る舞いを実現する手段と なる。クラスは複数のインターフェースを実装することができ、それぞれのインターフェースで定義 されたメソッドを実装する必要がある。 (次ページに続く) 親クラス 親クラスの機能 子クラス 親クラスの機能 子クラスの機能 継承 ★インターフェース 2 ページ
  3. インターフェースの(大規模開発における)重要性 インターフェースを使用することで、モジュールの結合度を弱くし、変更に強い設計を実現するこ とができる。 インターフェースによって境界を定めることで、各モジュールはそのインターフェースに従ってコ ミュニケーションを行う。各モジュールは自身の内部実装を隠蔽し、他のモジュールが必要な機能 に対してはインターフェースを通じて提供するため、これにより、モジュール間の結合度が低くな り、あるモジュールの変更が他のモジュールに影響を与えにくくなる 大規模開発では、機能の追加や変更が頻繁に行われることがあり、その際、インターフェースに よってモジュール間の契約が明確になっているため、変更が生じた場合でも関連するモジュールの 修正が容易になる。また、モジュールの独立性が高まるため、単体でのテストや再利用も容易にな

    ります。 したがって、インターフェースを使用することで、大規模開発において変更に強く、モジュール結 合度が弱くなるというメリットがある 継承 or インターフェース 継承は適切に使用しないと複雑な階層構造やクラス間の強い結合が生じる可能性があり、インター フェースはそれを実装したクラス間の緩い結合と柔軟性を提供するため、インターフェースをなる べく使うのが望ましい モジュール結合度と凝集度 モジュール結合度 プログラムの健全度を表す概念としてモジュール結合度と凝集度が挙げられる 一般的にモジュール結合度は低く、凝集度は高い方が良い(高凝集・疎結合) モジュール結合度(Coupling)は、モジュール間の依存度や結びつきの度合いを表す。結合度が 低い場合、モジュール間の依存が少なく、変更が発生した場合でも他のモジュールに影響を与え にくくなる。疎結合なモジュールは、単独でのテストや再利用が容易であり、システム全体の柔 軟性や保守性を高める (次ページに続く) 3 ページ
  4. モジュール凝集度 同じクラスやパッケージ等に同類の役割のモジュールや処理が集まっているかどうか 凝集度(Cohesion)は、モジュール内の要素がどれだけ密に関連しているかを表す。凝集度が高 い場合、モジュール内の要素が一つの責務や目的に集中しており、役割が明確になっている。ま た同じようなモジュールがパッケージ内に集まっている場合でも、それらが共通の目的や関心事 に関連しているのであれば、高凝集といえる。高凝集なモジュールは、機能の追加や変更が容易 であり、モジュール内の理解や保守がしやすくなる ポリモーフィズム(多態性 / 多相性

    ) ポリモーフィズムは、オブジェクト指向の重要な特性であり、ソフトウェアの柔軟性、拡張 性、保守性を高めるために利用される。正しく活用することで、コードの効率性や再利用性を 向上させ、複雑なシステムをより理解しやすくすることができる。 ポリモーフィズムは、同じメソッド名を持つ異なるオブジェクトが、それぞれ固有の実装を持 つことによって、異なる動作を実現する機能です。具体的には、親クラスやインターフェース を共有する複数のサブクラスがあり、それぞれが同じメソッド名を持つ場合にポリモーフィズ ムが発揮されます。 カプセル化 カプセル化は、オブジェクトの内部の状態や振る舞いを隠蔽し、外部からのアクセスを制限する こと。オブジェクトは自身の内部にデータを保持し、そのデータに対する操作をメソッドを通じ て提供する。これにより、データの状態を安全に保ちながら、外部からの不正な変更やアクセス を防ぐことが可能になる しかしながら、完全に結合度をゼロにすることや、完全に凝集度を最大化することは現実的では なく、設計上のトレードオフが存在することも多く、特定の状況や要件に応じて最適なバランス を見つける必要がある 現実世界 Java サイレン サイレンを鳴らす(機能) Siren siren; void soundSiren(); public class Car { // 自動車の機能 ... } public class PoliceCar extends Car { private Siren siren; public void soundSiren() { this.siren.sound(); } } 4 ページ
  5. オーバーライド オーバーライド(Override)は、ポリモーフィズムの一形態でサブクラス(派生クラス)がスー パークラス(基底クラス)のメソッドを再定義することを意味する。サブクラスは基本スーパーク ラスのメソッドを継承するが、そのメソッドの振る舞いを変更(上書き)する必要がある場合に オーバーライドを使用する。 具体的には、スーパークラスで定義されたメソッドと同じシグネチャ(メソッド名、引数の型およ び順序)を持つメソッドをサブクラスで再度定義し、そのメソッドの実装をオーバーライドする。 これにより、サブクラスで新しい実装を提供することができる。 オーバーロード オーバーロード(Overload)は、静的なポリモーフィズムの一形態で、同じメソッド名を持つ

    が、引数の型、数、および順序が異なる複数のメソッドを定義することを指す。これにより、 同じ名前のメソッドを異なる引数で呼び出すことができるようになるため、同じ操作や処理の 異なるバリエーションを提供することができる。 public class Computer { ... public void initialize(String env) {...} public void initialize(int archType) {...} public void initialize(String env, int archType) {...} public void initialize(int archType, String env) {...} ... } 同じメソッド名でも引数の 型、個数または並びが異なっ ているので、別のメソッドと してみなされる 親クラス void execute() { 処理 A; } 子クラス void execute() { 処理 B; } 継承 オーバーライド メソッドのオーバーロードの例 5 ページ
  6. キャスト 明示的キャスト キャスト (Cast) は、プログラムにおいてデータ型の変換を行う操作のことで、明示的キャストと 暗黙的キャストの2種類がある 暗黙的キャスト 抽象型とは 抽象型は、例えば、継承元の親クラスの型やインターフェースの型を指し、ポリモーフィズムの 実現やコードの再利用性の向上に貢献する。抽象型を使用することで、異なる具体的な型のオブ

    ジェクトを統一的に扱うことができ、また、抽象型を継承したり実装したりすることで、共通の インターフェースや振る舞いを持つクラスを効率的に作成することができる。 例えば以下のAutomobileというinterfaceを実装したTruckとSedanのオブジェクトは同じAutomobile という抽象形で表現できる 以下はどちらもAutomobile Automobile truck = new Truck(); Automobile sedan = new Sedan(); プログラマが明示的にキャスト演算子を使用して型変換を行う操作で、データの精度や範囲の損 失が発生する可能性があるため、注意が必要。 また、明示的キャストは呼び出し元と呼び出し先のモジュール間の結合度を低く抑える上で、な るべく多用しないことが望ましい // 暗黙的キャスト Automobile truck = new Truck(); // 明示的キャスト Truck truck = (Truck)truck; 暗黙的キャストは、コンパイラによって自動的に行われるデータ型の変換で、プログラムの可読 性を向上させ、コードを簡潔に保つことができ、モジュール結合度を低める傾向がある。しかし、 暗黙的なキャストが行われる場合でも、データの損失や予期しない結果が発生する可能性がある ため、注意が必要。 6 ページ
  7. ポインタはメモリ上の特定のデータのアドレスを直接示す変数で、ポインタはそのアドレスを通 じてデータにアクセスすることができる。CやC++などの言語ではポインタが使用され、メモリの 直接的な制御や効率的なデータ操作が可能になっている。 参照型 プリミティブ型 プリミティブ型は基本的なデータ型であり、数値、文字、真偽値などの単一の値を表す。一般的 なプリミティブ型には、整数型(int、long)、浮動小数点型(float、double)、文字型(char)、 真偽値型(boolean)などがあるが、プリミティブ型の変数は、その値そのものを直接格納する。 一方、参照型の変数は、オブジェクトへの参照値を格納する。参照型の変数が実際に保持してい るのは、オブジェクトへの参照(リンク)であり、その参照を通じてオブジェクトのメソッドや

    プロパティにアクセスすることができる。 ポインタ・参照値 ポインタ 参照値は変数やオブジェクトへの別名(エイリアス)として機能する値。参照値は元の変数やオ ブジェクトを参照し、同じデータに対して別の名前を提供する。JavaやC#などの言語では参照値が 使用され、参照値を通じてオブジェクトにアクセスすることで、データの共有やオブジェクトの 操作が可能になっている。 ポインタとの違いは、つまり参照値はオブジェクトのメモリのアドレスと変数の間を仲介する間 接的な値であり、ポインタは直接的なアドレス値を持つ値である 参照値 参照型とプリミティブ型 参照型とプリミティブ型は、プログラミング言語における変数のデータ型の2つの主要なカテゴリ に該当する プリミティブ型と参照型の違いは、変数が直接的な値を格納するか、参照を格納するかという点 で、それにより、値のコピーと変更の挙動などが異なることに注意 7 ページ
  8. Java 8以降のJava言語 Kotlin Scala Groovy Swift 関数型とオブジェクト指向 関数型プログラミングは、その純粋性と数学的な厳密さが、特に並行性や並列性、大規模なシステム の予測可能な動作、およびバグの少ないコードの作成において高く評価されいる。これに対し、オブ ジェクト指向プログラミングは、システムを直感的にモデル化しやすく、現実世界の問題に対する直

    接的なアプローチを提供するため広く採用されている オブジェクト指向と関数型の融合 また、多くの現代の言語やフレームワークでは、これらのパラダイムが組み合わされていることが多 く、関数型のコンセプトをオブジェクト指向言語でサポートしていることも多い(例:Javaのスト リームAPI、C#のLINQ)。このように、パラダイム間の境界が徐々にぼやけ、オブジェクト指向と関数 型のそれぞれの⾧所を活かすために、それらを併せ持った言語が使われることが増えている 関数型の特徴 ・出力は入力のみによって決まる(副作用を抑えやすい) ・関数内部に状態を持たない(状態レス) ・関数同士が、互いに依存せず、疎結合としやすい 関数型インターフェースを持つ主な言語 スクリプト系言語でも多くが関数型プログラミングの機能を備えている JavaScript、Lua、Perl、Python、PHP、Ruby 8 ページ