プログラミングにおける抽象化とは?
プログラミングにおける抽象化とは、何かがどう動くのかという詳細をより単純なインタフェースの後ろに隠し、それが何をするのかだけを知っていれば使えるようにすることです。sorted(names) を呼べば、並べ替えのアルゴリズムを自分で書くことも、目にすることもなく、リストを並べ替えられます。
更新日: 2026年9月24日
print("hi") と書くとき、その文字がどうやって画面に届くのかを考えることはありません。その1行の下で、Pythonはテキストをバイトに変換してオペレーティングシステムに書き込みを頼み、オペレーティングシステムはそれをターミナルに渡し、ターミナルはフォントを使って各文字をピクセルとして描きます。どの層も、1つ上の層に単純な約束を提供し、その約束をどう守っているかを隠しています。この隠すことが抽象化であり、どのプログラムもこうした層を何枚も重ねた上に乗っています。
抽象化のレベル
| レベル | 扱うもの | 隠しているもの |
|---|---|---|
| あなたのプログラム | print("hi")、sorted(names) | ライブラリがどう仕事をしているか |
| Pythonとその標準ライブラリ | 文字列、リスト、ファイル | メモリ管理、システムコール |
| インタプリタ(CPython) | バイトコード | それを実行するCのコードとマシンコード |
| オペレーティングシステム | ファイル、プロセス | ディスクのブロック、デバイスドライバ、CPUのスケジューリング |
| ハードウェア | 機械語の命令 | トランジスタと電気信号 |
どのレベルも1つ下のレベルから作られていて、下のレベルを知らなくても理解できます。ディスクのブロックが何かを知らなくても動くPythonのコードは書けますし、オペレーティングシステムはファイルの中身がPythonのコードだと知らなくてもそれを保存できます。
コードの中の抽象化の仕組み
プログラマは、主に2つの方法で自分の層を作ります。
手続きの抽象化とは関数のことです。名前、引数、戻り値がインタフェースで、本体が隠された詳細です。average(scores) ができてしまえば、プログラムの残りの部分は、それがどう足して割っているかを読まずに使えます。
データの抽象化は、型を、どう保存するかではなく、それで何ができるかによって定義します。キューとは「後ろに追加し、前から取り出す」ものです。要素がメモリ上にどう並んでいるかは、内部だけの判断です。
serving soup
serving pasta
serving cake
下のほうのコードは deque について何も知りません。これを普通のリストと pop(0) に置き換えても、出力はまったく同じです。違うのは、長いキューで遅くなることだけです。リストの最初の要素を取り除くと、ほかの要素がすべて移動するからです。インタフェースが変わらなかったので、クラスの外は何も変更する必要がありませんでした。
抽象クラスとインタフェース
オブジェクト指向プログラミングでの抽象化は、ふつう、一群のクラスが何をしなければならないかを定め、どうするかは各クラスに任せることを意味します。Pythonでは abc モジュールでメソッドを抽象メソッドとして指定します。実装されていない抽象メソッドを持つクラスは、インスタンスを作れません。
email to ana@example.com: Your package arrives today
sms to +15550100: Your package arrives today
Notifier is abstract: create an Email or an SMS instead
remind() が依存しているのは抽象化だけ、つまり send メソッドを持つものなら何でもよい、ということです。プッシュ通知を追加するには新しいクラスを1つ書くだけで、remind() には手を付けずに済みます。この最後のステップ、つまり1つの呼び出しがクラスによって違うコードを実行することがポリモーフィズムです。抽象化が共通のインタフェースを定め、ポリモーフィズムがそれを機能させるのです。
Javaには、同じ道具がキーワードとして用意されています。
interface Notifier {
void send(String to, String text);
}
class Email implements Notifier {
public void send(String to, String text) { /* talk to the mail server */ }
}
new Notifier() と書くとコンパイルエラーになります。インタフェースには実行できる実装がないからです。Javaの抽象クラスとインタフェースについては、ドキュメントで詳しく説明しています。
抽象化とカプセル化の違い
2つの考え方は一緒に登場することが多いので、混同しやすいです。
| 抽象化 | カプセル化 | |
|---|---|---|
| 答える問い | これは何をするのか? | 誰がデータに触れてよいのか? |
| 注目するところ | インタフェース、つまり提供される操作 | 内部、つまりインタフェースの背後にあるデータ |
| 主な道具 | 関数、抽象クラス、インタフェース、モジュール | private、_name、プロパティ、#fields |
| 例 | Notifier.send() がメールにもSMSにも使える | _balance は withdraw() を通してしか変わらない |
| レベル | 設計 | 実装 |
抽象化はどの操作を見せるかを決め、カプセル化は残りが確実に隠れたままになるようにします。上の Queue は両方を行っています。add と next が抽象化で、_items のアンダースコアがカプセル化です。
漏れのある抽象化とその他の間違い
ジョエル・スポルスキーは2002年に漏れのある抽象化の法則を名付けました。それなりに複雑な抽象化はどれも、隠している詳細の一部を漏らしてしまう、というものです。浮動小数点数はその典型的な例です。普通の小数のように見えますが、下にある2進数での保存形式が表に出てくることがあります。
0.30000000000000004
False
0.1も0.2も2進数のビットでは正確に保存できないので、合計がわずかにずれます。何年もこのことを考えずに浮動小数点数を使い続けることはできますが、永遠にとはいきません。だからこそ、自分が作業している層の1つ下の層を知っておくと役に立つのです。
ほかにもよくある間違いが2つあります。
- 早すぎる抽象化。 いつまでも来ないケースのために作られたクラスの階層は、読んで変更しなければならないコードを増やすだけです。サンディ・メッツはこれを「重複は、間違った抽象化よりはるかに安上がりだ」と表現しました。
- 抽象化を
abstractキーワードと混同する。 抽象クラスは道具の1つにすぎません。うまく名前の付いた関数も、どれも抽象化です。
次に読むページ
オブジェクト指向の全体像をつかむには、カプセル化とポリモーフィズムを読んでください。オペレーティングシステムのページでは、プログラムが頼っている最大の抽象化を紹介しています。練習するなら、Pythonコースでは最初からクラスと関数を作っていき、Javaコースでは抽象クラスとインタフェースを扱います。
よくある質問
抽象化の具体例は?
len(items) は、Pythonがどう数えるかではなく、何を返すかを知っていれば呼べます。日常の例なら車のペダルで、エンジンがどう燃料を燃やしているかを知らなくても速度を操作できます。オブジェクト指向のコードでは、send メソッドを1つだけ持つ Notifier のようなインタフェースが、メール、SMS、プッシュ通知をまとめる抽象化になります。Pythonの抽象化とは?
abc モジュールを使うと @abstractmethod で抽象基底クラスを宣言できます。するとPythonは、そのクラスのオブジェクトも、抽象メソッドをすべて実装していないサブクラスのオブジェクトも作らせません。Javaプログラミングの抽象化とは?
new でインスタンスを作れません。インタフェースは、実装するクラスが必ず用意しなければならないメソッドを並べたもので、1つのクラスが複数のインタフェースを実装できます。