どっちを学ぶべき?関数型 vs オブジェクト指向【新人エンジニア向け比較ガイド】
こんにちは。ゆうせいです。
これまでの記事で、副作用のないクリーンな「純粋関数」という考え方についてお話ししましたね。
実は、あの純粋関数は「関数型プログラミング」という、大きな設計思想の一部なんです。そして、プログラミングの世界にはもう一つ、非常に有名で広く使われている「オブジェクト指向プログラミング」という考え方が存在します。
新人エンジニアの皆さんにとっては、「一体どっちを学べばいいの?」「何がどう違うの?」と、少し混乱してしまうかもしれません。
今回は、この二大巨頭とも言える考え方が、それぞれどんな哲学を持っているのか、具体的なPythonコードを交えながら分かりやすく解説していきます!
2つのプログラミング哲学
まず大前提として、どちらが優れていて、どちらが劣っているという話ではありません。
これは、料理で言うところの「フレンチの哲学」と「日本料理の哲学」のようなもの。どちらも素晴らしい料理を作るための方法論ですが、素材へのアプローチや考え方が違うのです。
- オブジェクト指向プログラミング (OOP):現実世界の「モノ」を主役にする考え方です。データ(状態)と、そのデータを操作する手続き(振る舞い)を一つの「オブジェクト」としてまとめ、モノ同士の相互作用としてプログラムを組み立てていきます。
- 関数型プログラミング (FP):データの「変換」や「流れ」を主役にする考え方です。純粋関数を使い、あるデータをインプットとして受け取り、新しいデータをアウトプットとして返す、という処理の連鎖としてプログラムを組み立てていきます。
例え話:自動車工場のアプローチ
言葉だけだとイメージしづらいので、自動車を作る工場で例えてみましょう。
それぞれの考え方を、Pythonのコードで表現するとどうなるか、見比べてみてください。
オブジェクト指向(OOP)工場:役割分担された専門家チーム
OOPの工場では、「エンジン担当」「タイヤ担当」「塗装担当」といった、それぞれが独立した専門家「オブジェクト」がいるんでしたね。車というオブジェクトの状態を、専門家オブジェクトがメッセージを受け取って変更していきます。
これをPythonのコードで表現すると、こんな雰囲気になります。
データ(色やエンジンの状態)と振る舞い(paintメソッド)が Car というクラスにまとめられている点に注目してください。
# OOPのアプローチ例
class Car:
# Carオブジェクトは自分自身の状態(色など)を知っている
def __init__(self):
self.color = None
self.engine = None
# 塗装という「振る舞い」を持つ
def paint(self, color):
print(f"{color}に塗装します")
self.color = color
# エンジン搭載という「振る舞い」を持つ
def mount_engine(self, engine_type):
print(f"{engine_type}を搭載します")
self.engine = engine_type
# --- 車の製造 ---
# 1. まずは車オブジェクトを作る
my_car = Car()
print(f"製造開始時の車の状態: 色={my_car.color}, エンジン={my_car.engine}")
# 2. 車オブジェクトに「塗装して」というメッセージを送る
my_car.paint("赤")
# 3. 車オブジェクトに「エンジンを搭載して」とメッセージを送る
my_car.mount_engine("V8エンジン")
print(f"完成した車の状態: 色={my_car.color}, エンジン={my_car.engine}")
my_car
というオブジェクト自身が、paint
などのメソッド(振る舞い)によって状態を変化させていく様子がわかりますね。
関数型(FP)工場:巨大なベルトコンベアと専門機械
一方、FPの工場は、ベルトコンベアを流れるデータ(車の情報)を、各工程の機械(関数)が次々と変換していくイメージでした。
こちらの考え方をPythonで表現してみましょう。
車の状態はシンプルな辞書で表現し、それを変更するのではなく、新しい辞書を返す「純粋関数」を定義している点に注目してください。
# FPのアプローチ例
# 塗装を行う純粋関数
# 車の情報(辞書)と色を受け取り、「新しい」車の情報を返す
def paint(car_info, color):
print(f"{color}に塗装します")
# 元の辞書をコピーして変更(イミュータブルの思想)
new_car_info = car_info.copy()
new_car_info["color"] = color
return new_car_info
# エンジンを搭載する純粋関数
def mount_engine(car_info, engine_type):
print(f"{engine_type}を搭載します")
new_car_info = car_info.copy()
new_car_info["engine"] = engine_type
return new_car_info
# --- 車の製造 ---
# 1. まずは元のデータ(車の初期情報)を用意
initial_car = {"color": None, "engine": None}
print(f"製造開始時の車の情報: {initial_car}")
# 2. 初期情報をpaint関数に通し、新しい情報を得る
car_after_paint = paint(initial_car, "赤")
# 3. 塗装済みの情報をmount_engine関数に通し、さらに新しい情報を得る
finished_car = mount_engine(car_after_paint, "V8エンジン")
print(f"完成した車の情報: {finished_car}")
print(f"元の車の情報は変わらない: {initial_car}")
データと処理(関数)が完全に分離されており、関数は副作用なく新しいデータを返すだけ。まるでベルトコンベアをデータが流れていくように見えませんか?
考え方の違いまとめ
この例え話から、両者の思想的な違いをまとめてみましょう。
観点 | オブジェクト指向 (OOP) | 関数型 (FP) |
主役 | モノ(オブジェクト) | データの変換(関数) |
関心事 | 責務の分割。誰が何をするか。 | データの流れ。どうデータが変わっていくか。 |
データ | 振る舞いとセットでカプセル化する | 振る舞い(関数)とは分離して考える |
状態の扱い | オブジェクトが自身の状態を管理・変更する | 状態の変更を避け、不変(イミュータブル)を好む |
まとめ:どちらを学ぶべきか?
ここまで読んで、「なるほど、考え方が全然違うんだな」と感じていただけたでしょうか。
では、新人エンジニアの皆さんはどちらを学べばよいのでしょう?
答えは、「両方の基本的な考え方を学ぶべき」です。
なぜなら、現代の多くのプログラミング言語(Python, JavaScript, C#, Javaなど)は、どちらか一方に特化しているわけではなく、両方のパラダイムの良いところを取り入れた「マルチパラダイム言語」だからです。
実際の開発では、アプリケーションの全体的な骨格はオブジェクト指向で作り、データの複雑な計算や変換処理の部分は関数型の考え方を使ってクリーンに書く、といったハイブリッドなアプローチが非常に多く取られています。
- まずはOOPから: 多くの現場で基本とされている考え方なので、クラスやインスタンスといったOOPの基本概念はしっかりと押さえましょう。「継承」や「ポリモーフィズム」といったキーワードも、いずれ学ぶことになります。
- 次にFPのエッセンスを: その上で、純粋関数やイミュータブルなデータといったFPの考え方を学ぶと、コードの質を一段階引き上げることができます。
二つの哲学は対立するものではなく、あなたの引き出しを増やしてくれる強力な武器です。それぞれの良さを理解し、適材適所で使い分けられるエンジニアを目指していきましょう!
投稿者プロフィール
- 代表取締役
-
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。
最新の投稿
山崎講師2025年10月11日属人化を防ぐ!再現性と網羅性を高めるテスト設計の基本
全ての社員2025年10月11日交渉で損しない!エンジニアが知るべきBATNAとZOPAの関係とは?
山崎講師2025年10月10日【AI開発の登竜門】Google製ライブラリ「TensorFlow」とは?新人エンジニア向けに徹底解説!
山崎講師2025年10月10日【入門】scikit-learnとは?機械学習の「家庭教師」を新人エンジニア向けに徹底解説!