🕐 ~8分間の読み物
📝 この記事に関するメモ
この投稿は私のOOPとSOLID原則に関する個人的な学習ノートに基づいています。これらのノートをより読みやすく、役立つものにするために——自分自身だけでなく他の人のために——AIと協力して、それらを適切なブログ形式に拡張して構造化しました。アイデア、学習の旅、理解は私のものですが、AIは執筆とプレゼンテーションを手伝いました。
良いコードは偶然では生まれない。使いやすいコードベースの背後には、物事の構造や接続方法を導く考え方がある。
本記事では、その全体の旅をカバーする——OOPとは何か、オブジェクトの関係性、悪い設計の見た目、そして最終的には、それをすべて結びつけるSOLIDの5つの原則について.
さあ始めよう.
第1部:OOPとは何か
オブジェクト指向プログラミング(OOP)は、現実世界を反映する方法でコードを書くものです。長い命令の一覧ではなく、関連するデータと行動をオブジェクトにまとめます。
🤖ロボットの玩具を考えてみてください。それはプロパティ(色、高さ、バッテリー)と行動を持っています (歩く、話す、振る). オブジェクト指向プログラミングでは、そのロボットはオブジェクトであり、それを構築するための設計図はクラスと呼ばれます。
二つの重要な用語:
- クラス — 設計図(テンプレート)
- オブジェクト — 設計図から構築された実際のインスタンス
四つの柱
| 柱 | その機能 |
|---|---|
| 継承 | 子クラスは親クラスからプロパティと振る舞いを継承します |
| カプセル化 | 内部データは隠され、外部からは制御されたアクセスのみが許可されます |
| 抽象化 | 複雑な内部は隠され、必要なものだけが公開されます |
| 多態性 | 同じアクションが対象によって異なる挙動を示すことがあります |
第2部:オブジェクトの関連性
オブジェクトは孤立して存在しません。それらは相互に接続し、協力し、依存し合い——そして関係の性
関連付け
二つのオブジェクトはお互いを知り、相互作用できます。三つの基本的なカーディナリティがあります:
- 一对一 — 一人一護照
- 一对多 — 一名教師、多名學生
- 多对多 — 多名學生、多門課程
内部關聯,當一個對象「擁有」另一個對象時,關係是:
- 聚合 (緩い) — 子供は親なしで生き残る。バックパックには本が入っているが、バックパックを捨てても本は存在する。
- 組成 (緊密) — 子供は親なしでは存在できない。家には部屋がある;家を破壊すれば、部屋は存在しなくなる。
依存関係
一時的な、使用に基づく関係。一つのクラスが別のクラスをメソッド内で使用するが、永続的に保持しない。関連性よりも弱い.
一般化 & 執行
- 一般化 — 複数のクラスから共有する特徴を一つのスーパークラスに引き込む(継承)
- 執行 — インターフェースを実装するクラスで、定義された契約を果たすことを約束しています
第3部:悪い設計の見た目
ルールを学ぶ前に、守るべきものを理解することが役立ちます。ロバート・C・マーティンは、悪い設計の三つの症状を特定しました
🪨 働きにくさ — システムを変更するのは難しい。一つを触れると、他の多くのことを更新する必要がある。開発者は変更を恐れるようになる。
🍪 弱さ — 変更を加えると、予期せぬ場所でシステムが壊れる。決済モジュールのバグを修正したら、何らかの理由でメール通知が動作しなくなる。
🏗️ 固着 — 有用なコンポーネントは再利用できません。それらはその周囲と非常に絡み合っているため、抽出するには元から書き直すよりも時間がかかります.
これら三つは同じ根本原因を共有しています: コンポーネント間の依存関係の管理が悪いです.
第4章: SOLID
SOLIDは、上記の問題に直接対応する五つの原則のセットです。それぞれが特定の失敗モードをターゲットとしています。
S — 単一責任の原則
「モジュールは、たった一つ、そしてそれ以上の役割に対して責任を持つべきである。」
各クラスは正確に一つの変更の理由を持つべきである — それは一つの役割(一つのステークホルダーグループ)をサービスする。
👨🍳 同時にシェフ、レジ係、警備員、配達員を務めるレストランの従業員は、ある役割の変更で他のすべての役割が混乱するような、避けられない災害を引き起こしている。
クラスを分ける。一つずつ責任を持つ。
O — 開放/閉鎖原則
「ソフトウェアの成果物は拡張に対して開放で、修正に対しては閉鎖であるべき。」
新しい振る舞いを追加するにはをで拡張する—既存の動作しているコードを編集することでなく。
🔌電源コンセントは、コンセント自体を再配線することなく新しいデバイスを接続できる。それがOCPの動作である。
要件が変わったら、古いコードと新しいコードを並べて挿入する—動作しているものを書き換えない。
L — Liskovの置換原則
"SがTのサブタイプである場合、Tの型のオブジェクトはSの型のオブジェクトで置き換えられ、プログラムの正しさが変わらない。"
スーパークラスに対してサブクラスは完全に置き換え可能である必要がある。スーパークラスが約束するものは、サブクラスも守らなければならない。
🤖 親ロボットが料理できる場合、子ロボットも料理できる必要がある——エラーを投げたり、無視して何もしなかったりしない。
もしサブクラスが空のメソッド、スタブ実装、または「サポートされていません」という例外をスローしている場合 — それはリスコフの違反です.
I — インターフェース分離の原則
「クライアントは、使用しないインターフェースに依存させられないべきではない。」
不要なメソッドを実装するようにクラスに強制するような太いインターフェースを作らない.インターフェースを分割する をより小さく、集中したものに分割します。
🍴 スープを注文しただけなのに、レストランの客にステーキナイフ、スープスプーン、箸、フォンデュスケーサーを全部与えるのはやめましょう。
小さなインターフェース = 狭い依存関係 = 変更がローカル化されます。
D — 依存関係逆転の原則
「高レベルモジュールは低レベルモジュールに依存しない。両方とも抽象化に依存すべきである。」
ビジネスロジックは特定の実装にハードコーディングされるべきではありません。インターフェースとコミュニケーションを取り、低レベルの詳細はそれらのインターフェースを実装する必要があります。
🤖 ロボットの腕にスプーンを溶接しないでください。腕に標準のコネクターを付け、ツールを簡単に取り外せるようにしてください。
これはインフラストラクチャ(データベース、API、ファイルシステム)をビジネスロジックを触らずに交換できることを意味します
クイックリファレンス:SOLIDの概要
| 原則 | 解決する問題 | 尋ねるべき鍵の質問 |
|---|---|---|
| SRP | クラスが多すぎる | 「このクラスは複数の利害関係者のグループをサービスするか?」 |
| OCP | 古いコードを機能追加のため編集しています | 「この機能を拡張として追加するのはどうでしょうか」 |
| LSP | 継承階層の破損 | 「子要素を親要素に置き換えると何も壊れないか?」 |
| ISP | 不要なメソッドが多いインターフェース | 「このクラスは不要なものを実装する義務があるのか?」 |
| DIP | ビジネスロジックがインフラにロックされている | 「私の高レベルコードが、必要でない具象クラスに依存しているのか?」 |
どこから始めるべきか
初めてこれらを適用する場合:
- SRPから始める — "やっていることが多すぎる"クラスを見つけ、それらを分割
- LSP違反の継承を確認 — 空のメソッドは警告の兆候
- インフラストラクチャの境界でインターフェースを導入 — これはDIPの実践
これらの原則はチェックリストではありません。コードを書くたびに尋ねるべき質問です。
最初公開于sanudin.dev











