サザエさんで学ぶ抽象クラスとインターフェースの違いと使い分け
![]() |
20万件以上の案件から、副業に最適なリモート・週3〜の案件を一括検索できるプラットフォーム。プロフィール登録でAIスカウトが自動的にマッチング案件を提案。市場統計や単価相場、エージェントの口コミも無料で閲覧可能なため、本業を続けながら効率的に高単価の副業案件を探せます。フリーランスボード |
| |
週2〜3日から働ける柔軟な案件が業界トップクラスの豊富さを誇るフリーランスエージェント。エンド直契約のため高単価で、週3日稼働でも十分な報酬を得られます。リモートや時間フレキシブルな案件も多数。スタートアップ・ベンチャー中心で、トレンド技術を使った魅力的な案件が揃っています。専属エージェントが案件紹介から契約交渉までサポート。利用企業2,000社以上の実績。ITプロパートナーズ |
| |
10,000件以上の案件を保有し、週3日〜・フルリモートなど柔軟な働き方に対応。高単価案件が豊富で、報酬保障制度(60%)や保険料負担(50%)など正社員並みの手厚い福利厚生が特徴。通勤交通費(月3万円)、スキルアップ費用(月1万円)の支給に加え、リロクラブ・freeeが無料利用可能。非公開案件80%以上、支払いサイト20日で安心して稼働できます。Midworks |
オブジェクト指向プログラミングを学ぶ上で、「抽象クラス」と「インターフェース」は重要な概念ですが、初心者にとっては理解が難しいテーマの一つです。
本記事では、国民的アニメ「サザエさん」の磯野家を例に、抽象クラスとインターフェースの違いを分かりやすく解説します。Pythonのコード例を交えながら、実践的な使い方まで学んでいきましょう。
目次
抽象クラスとは?サザエさん家族で理解する
抽象クラスとは、他のクラスの「ひな形」となる、インスタンス化できないクラスのことです。共通の特徴を持つクラス群の基底クラスとして機能します。
磯野家の家族を例にした抽象クラス
磯野家の家族は全員「磯野家の一員」という共通点があります。そして、全員が「挨拶をする」「食事をする」といった共通の行動をします。ただし、その具体的な方法は人それぞれ異なります。
from abc import ABC, abstractmethod
class 磯野家の家族(ABC):
"""磯野家の家族を表す抽象クラス"""
def __init__(self, name, age):
self.name = name
self.age = age
self.family_name = "磯野"
@abstractmethod
def 挨拶する(self):
"""各キャラクターが独自の挨拶をする(抽象メソッド)"""
pass
@abstractmethod
def 日常の活動(self):
"""各キャラクターの日常活動(抽象メソッド)"""
pass
def 家族紹介(self):
"""全員共通の家族紹介メソッド(具象メソッド)"""
return f"私は{self.family_name}{self.name}、{self.age}歳です"
class サザエ(磯野家の家族):
def __init__(self):
super().__init__("サザエ", 24)
def 挨拶する(self):
return "あら〜、いらっしゃ〜い!"
def 日常の活動(self):
return "買い物をしたり、料理を作ったりしています"
def 家事をする(self):
"""サザエ独自のメソッド"""
return "今日も家事を頑張ります!"
class カツオ(磯野家の家族):
def __init__(self):
super().__init__("カツオ", 11)
def 挨拶する(self):
return "ちわー!"
def 日常の活動(self):
return "学校に行ったり、友達と遊んだりしています"
def イタズラする(self):
"""カツオ独自のメソッド"""
return "中島〜、野球しようぜ!"
# 使用例
sazae = サザエ()
katsuo = カツオ()
print(sazae.家族紹介()) # 私は磯野サザエ、24歳です
print(sazae.挨拶する()) # あら〜、いらっしゃ〜い!
print(sazae.日常の活動()) # 買い物をしたり、料理を作ったりしています
print(katsuo.家族紹介()) # 私は磯野カツオ、11歳です
print(katsuo.挨拶する()) # ちわー!
print(katsuo.日常の活動()) # 学校に行ったり、友達と遊んだりしています
抽象クラスのポイント
- 共通の属性を持つ:
name、age、family_nameなど、全ての家族が共有する属性 - 共通の具象メソッドを持つ:
家族紹介()のように、実装が共通のメソッド - 抽象メソッドを持つ:
@abstractmethodで定義された、サブクラスで必ず実装すべきメソッド - インスタンス化できない:
磯野家の家族()と直接インスタンス化することはできない
インターフェースとは?役割で理解する
インターフェースとは、クラスが実装すべきメソッドの「契約」を定義するものです。「何ができるか」を規定しますが、「どのように実装するか」は各クラスに任されます。
Pythonには厳密なインターフェースの概念はありませんが、抽象基底クラスで実装が可能です。
サザエさんキャラクターの「役割」をインターフェースで表現
磯野家の家族は、それぞれ異なる「役割」を持っています。サザエは「主婦」、マスオは「サラリーマン」、カツオは「学生」といった具合です。
from abc import ABC, abstractmethod
# インターフェース:主婦の役割
class 主婦インターフェース(ABC):
@abstractmethod
def 料理を作る(self):
pass
@abstractmethod
def 洗濯をする(self):
pass
@abstractmethod
def 掃除をする(self):
pass
# インターフェース:サラリーマンの役割
class サラリーマンインターフェース(ABC):
@abstractmethod
def 出勤する(self):
pass
@abstractmethod
def 仕事をする(self):
pass
@abstractmethod
def 帰宅する(self):
pass
# インターフェース:学生の役割
class 学生インターフェース(ABC):
@abstractmethod
def 登校する(self):
pass
@abstractmethod
def 勉強する(self):
pass
@abstractmethod
def 宿題をする(self):
pass
# 実装クラス:サザエ(主婦の役割を実装)
class サザエ実装(主婦インターフェース):
def __init__(self):
self.name = "サザエ"
def 料理を作る(self):
return f"{self.name}:今日の夕飯はカレーよ!"
def 洗濯をする(self):
return f"{self.name}:洗濯物を干さなきゃ"
def 掃除をする(self):
return f"{self.name}:お部屋をきれいにしましょう"
# 実装クラス:マスオ(サラリーマンの役割を実装)
class マスオ実装(サラリーマンインターフェース):
def __init__(self):
self.name = "マスオ"
def 出勤する(self):
return f"{self.name}:行ってきま〜す!"
def 仕事をする(self):
return f"{self.name}:今日も営業頑張るぞ"
def 帰宅する(self):
return f"{self.name}:ただいま〜、ビールが飲みたいなぁ"
# 実装クラス:カツオ(学生の役割を実装)
class カツオ実装(学生インターフェース):
def __init__(self):
self.name = "カツオ"
def 登校する(self):
return f"{self.name}:学校行ってきまーす!"
def 勉強する(self):
return f"{self.name}:う〜ん、算数は苦手だなぁ"
def 宿題をする(self):
return f"{self.name}:宿題めんどくさいなぁ..."
# 使用例
sazae = サザエ実装()
print(sazae.料理を作る()) # サザエ:今日の夕飯はカレーよ!
print(sazae.洗濯をする()) # サザエ:洗濯物を干さなきゃ
masuo = マスオ実装()
print(masuo.出勤する()) # マスオ:行ってきま〜す!
print(masuo.仕事をする()) # マスオ:今日も営業頑張るぞ
katsuo = カツオ実装()
print(katsuo.登校する()) # カツオ:学校行ってきまーす!
print(katsuo.勉強する()) # カツオ:う〜ん、算数は苦手だなぁ
インターフェースのポイント
- 実装を持たない: すべてのメソッドが抽象メソッド
- 複数実装が可能: 一つのクラスが複数のインターフェースを実装できる
- 「できること」を定義: 「何をするか」だけを定義し、「どうやるか」は実装クラスに任せる
- 契約の役割: インターフェースを実装したクラスは、必ず全てのメソッドを実装しなければならない
抽象クラスとインターフェースの違い
| 比較項目 | 抽象クラス | インターフェース |
|---|---|---|
| 目的 | クラスの共通部分を抽象化 | クラスの「能力」や「役割」を定義 |
| 具象メソッド | 持つことができる | 持たない(全て抽象) |
| 属性 | 持つことができる | 基本的に持たない |
| 多重継承 | 不可(単一継承のみ) | 可能(複数のインターフェース実装) |
| 関係性 | 「is-a」関係(〜である) | 「can-do」関係(〜できる) |
| 例 | カツオ is a 磯野家の家族 | サザエ can do 主婦の仕事 |
実践的な使い分け例:複数の役割を持つキャラクター
実際のプログラミングでは、一つのクラスが複数の役割(インターフェース)を実装することがよくあります。
from abc import ABC, abstractmethod
# 基底の抽象クラス
class キャラクター(ABC):
def __init__(self, name, age):
self.name = name
self.age = age
@abstractmethod
def 自己紹介(self):
pass
def 名前を取得(self):
return self.name
# インターフェース:料理ができる
class 料理可能(ABC):
@abstractmethod
def 料理を作る(self, dish):
pass
# インターフェース:仕事ができる
class 仕事可能(ABC):
@abstractmethod
def 仕事をする(self):
pass
# インターフェース:運転ができる
class 運転可能(ABC):
@abstractmethod
def 運転する(self, destination):
pass
# サザエ:料理ができて、運転もできる
class サザエ完全版(キャラクター, 料理可能, 運転可能):
def __init__(self):
super().__init__("サザエ", 24)
self.cooking_level = "上級"
def 自己紹介(self):
return f"私は{self.name}です。主婦をしています!"
def 料理を作る(self, dish):
return f"{self.name}が{dish}を作りました!得意料理です♪"
def 運転する(self, destination):
return f"{self.name}が{destination}まで車で行きます(たまに危ない運転...)"
# マスオ:仕事ができて、料理もできる
class マスオ完全版(キャラクター, 仕事可能, 料理可能):
def __init__(self):
super().__init__("マスオ", 28)
self.company = "海山商事"
def 自己紹介(self):
return f"私は{self.name}です。{self.company}で働いています"
def 仕事をする(self):
return f"{self.name}が{self.company}で営業の仕事をしています"
def 料理を作る(self, dish):
return f"{self.name}が{dish}を作りました。たまには料理も手伝います"
# 使用例
sazae = サザエ完全版()
print(sazae.自己紹介()) # 私はサザエです。主婦をしています!
print(sazae.料理を作る("カレー")) # サザエがカレーを作りました!得意料理です♪
print(sazae.運転する("商店街")) # サザエが商店街まで車で行きます(たまに危ない運転...)
masuo = マスオ完全版()
print(masuo.自己紹介()) # 私はマスオです。海山商事で働いています
print(masuo.仕事をする()) # マスオが海山商事で営業の仕事をしています
print(masuo.料理を作る("チャーハン")) # マスオがチャーハンを作りました。たまには料理も手伝います
# 型チェック
print(isinstance(sazae, キャラクター)) # True
print(isinstance(sazae, 料理可能)) # True
print(isinstance(sazae, 運転可能)) # True
print(isinstance(sazae, 仕事可能)) # False
いつ抽象クラスを使い、いつインターフェースを使うか
抽象クラスを使うべき場合
-
共通の実装を持つクラス群を作る時
- 例:磯野家の家族全員が共通の属性(姓、住所など)を持つ
-
「is-a」の関係を表現したい時
- 例:カツオは磯野家の家族である
-
段階的に機能を追加したい時
- 基底クラスで基本機能、サブクラスで拡張機能
class 磯野家(ABC):
def __init__(self, name):
self.name = name
self.address = "東京都世田谷区あさひが丘" # 共通の住所
def 住所を取得(self):
return self.address # 共通の実装
@abstractmethod
def 特徴(self):
pass # サブクラスで実装
インターフェースを使うべき場合
-
「できること」を定義したい時
- 例:料理ができる、運転ができる、仕事ができる
-
複数の異なる能力を組み合わせたい時
- 例:サザエは料理と運転の両方ができる
-
クラス間の関係が薄い時
- 例:サザエとマスオは両方料理ができるが、それ以外は異なる
# 複数のインターフェースを組み合わせる
class スーパー主婦(キャラクター, 料理可能, 運転可能, 仕事可能):
# すべての能力を持つキャラクター
pass
まとめ
抽象クラスとインターフェースは、どちらもオブジェクト指向プログラミングの重要な概念ですが、使い分けが大切です。
抽象クラスのまとめ
- クラスの「共通部分」を抽象化
- 具象メソッドと属性を持てる
- 「is-a」関係を表現
- 磯野家の例:全員が「磯野家の家族である」
インターフェースのまとめ
- クラスの「能力・役割」を定義
- すべて抽象メソッド
- 「can-do」関係を表現
- サザエさんの例:「料理ができる」「運転ができる」
実務での活用ポイント
- 共通の属性や実装がある → 抽象クラス
- 異なるクラスに共通の能力を持たせる → インターフェース
- 両方を組み合わせて柔軟な設計を実現
PythonではABC(Abstract Base Class)モジュールを使って、両方の概念を実装できます。継承関係や能力の定義を適切に設計することで、保守性が高く拡張しやすいコードを書くことができます。
サザエさんの世界観を通じて学んだこれらの概念を、ぜひ実際のプロジェクトで活用してみてください!
参考リソース
- Python公式ドキュメント – abc モジュール
- オブジェクト指向設計の原則(SOLID原則)
- デザインパターンと抽象化
この記事が、抽象クラスとインターフェースの理解に役立てば幸いです。サザエさんの例で覚えれば、もう忘れませんね!
![]() |
20万件以上の案件から、副業に最適なリモート・週3〜の案件を一括検索できるプラットフォーム。プロフィール登録でAIスカウトが自動的にマッチング案件を提案。市場統計や単価相場、エージェントの口コミも無料で閲覧可能なため、本業を続けながら効率的に高単価の副業案件を探せます。フリーランスボード |
| |
週2〜3日から働ける柔軟な案件が業界トップクラスの豊富さを誇るフリーランスエージェント。エンド直契約のため高単価で、週3日稼働でも十分な報酬を得られます。リモートや時間フレキシブルな案件も多数。スタートアップ・ベンチャー中心で、トレンド技術を使った魅力的な案件が揃っています。専属エージェントが案件紹介から契約交渉までサポート。利用企業2,000社以上の実績。ITプロパートナーズ |
| |
10,000件以上の案件を保有し、週3日〜・フルリモートなど柔軟な働き方に対応。高単価案件が豊富で、報酬保障制度(60%)や保険料負担(50%)など正社員並みの手厚い福利厚生が特徴。通勤交通費(月3万円)、スキルアップ費用(月1万円)の支給に加え、リロクラブ・freeeが無料利用可能。非公開案件80%以上、支払いサイト20日で安心して稼働できます。Midworks |








