サザエさんで学ぶ抽象クラスとインターフェースの違いと使い分け

フリーランスボード

20万件以上の案件から、副業に最適なリモート・週3〜の案件を一括検索できるプラットフォーム。プロフィール登録でAIスカウトが自動的にマッチング案件を提案。市場統計や単価相場、エージェントの口コミも無料で閲覧可能なため、本業を続けながら効率的に高単価の副業案件を探せます。フリーランスボード

ITプロパートナーズ

週2〜3日から働ける柔軟な案件が業界トップクラスの豊富さを誇るフリーランスエージェント。エンド直契約のため高単価で、週3日稼働でも十分な報酬を得られます。リモートや時間フレキシブルな案件も多数。スタートアップ・ベンチャー中心で、トレンド技術を使った魅力的な案件が揃っています。専属エージェントが案件紹介から契約交渉までサポート。利用企業2,000社以上の実績。ITプロパートナーズ

Midworks 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.日常の活動())  # 学校に行ったり、友達と遊んだりしています

抽象クラスのポイント

  1. 共通の属性を持つ: nameagefamily_nameなど、全ての家族が共有する属性
  2. 共通の具象メソッドを持つ: 家族紹介()のように、実装が共通のメソッド
  3. 抽象メソッドを持つ: @abstractmethodで定義された、サブクラスで必ず実装すべきメソッド
  4. インスタンス化できない: 磯野家の家族()と直接インスタンス化することはできない

インターフェースとは?役割で理解する

インターフェースとは、クラスが実装すべきメソッドの「契約」を定義するものです。「何ができるか」を規定しますが、「どのように実装するか」は各クラスに任されます。

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.勉強する())  # カツオ:う〜ん、算数は苦手だなぁ

インターフェースのポイント

  1. 実装を持たない: すべてのメソッドが抽象メソッド
  2. 複数実装が可能: 一つのクラスが複数のインターフェースを実装できる
  3. 「できること」を定義: 「何をするか」だけを定義し、「どうやるか」は実装クラスに任せる
  4. 契約の役割: インターフェースを実装したクラスは、必ず全てのメソッドを実装しなければならない

抽象クラスとインターフェースの違い

比較項目 抽象クラス インターフェース
目的 クラスの共通部分を抽象化 クラスの「能力」や「役割」を定義
具象メソッド 持つことができる 持たない(全て抽象)
属性 持つことができる 基本的に持たない
多重継承 不可(単一継承のみ) 可能(複数のインターフェース実装)
関係性 「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

いつ抽象クラスを使い、いつインターフェースを使うか

抽象クラスを使うべき場合

  1. 共通の実装を持つクラス群を作る時

    • 例:磯野家の家族全員が共通の属性(姓、住所など)を持つ
  2. 「is-a」の関係を表現したい時

    • 例:カツオは磯野家の家族である
  3. 段階的に機能を追加したい時

    • 基底クラスで基本機能、サブクラスで拡張機能
class 磯野家(ABC):
    def __init__(self, name):
        self.name = name
        self.address = "東京都世田谷区あさひが丘"  # 共通の住所
    
    def 住所を取得(self):
        return self.address  # 共通の実装
    
    @abstractmethod
    def 特徴(self):
        pass  # サブクラスで実装

インターフェースを使うべき場合

  1. 「できること」を定義したい時

    • 例:料理ができる、運転ができる、仕事ができる
  2. 複数の異なる能力を組み合わせたい時

    • 例:サザエは料理と運転の両方ができる
  3. クラス間の関係が薄い時

    • 例:サザエとマスオは両方料理ができるが、それ以外は異なる
# 複数のインターフェースを組み合わせる
class スーパー主婦(キャラクター, 料理可能, 運転可能, 仕事可能):
    # すべての能力を持つキャラクター
    pass

まとめ

抽象クラスとインターフェースは、どちらもオブジェクト指向プログラミングの重要な概念ですが、使い分けが大切です。

抽象クラスのまとめ

  • クラスの「共通部分」を抽象化
  • 具象メソッドと属性を持てる
  • 「is-a」関係を表現
  • 磯野家の例:全員が「磯野家の家族である」

インターフェースのまとめ

  • クラスの「能力・役割」を定義
  • すべて抽象メソッド
  • 「can-do」関係を表現
  • サザエさんの例:「料理ができる」「運転ができる」

実務での活用ポイント

  1. 共通の属性や実装がある → 抽象クラス
  2. 異なるクラスに共通の能力を持たせる → インターフェース
  3. 両方を組み合わせて柔軟な設計を実現

PythonではABC(Abstract Base Class)モジュールを使って、両方の概念を実装できます。継承関係や能力の定義を適切に設計することで、保守性が高く拡張しやすいコードを書くことができます。

サザエさんの世界観を通じて学んだこれらの概念を、ぜひ実際のプロジェクトで活用してみてください!


参考リソース

この記事が、抽象クラスとインターフェースの理解に役立てば幸いです。サザエさんの例で覚えれば、もう忘れませんね!

フリーランスボード

20万件以上の案件から、副業に最適なリモート・週3〜の案件を一括検索できるプラットフォーム。プロフィール登録でAIスカウトが自動的にマッチング案件を提案。市場統計や単価相場、エージェントの口コミも無料で閲覧可能なため、本業を続けながら効率的に高単価の副業案件を探せます。フリーランスボード

ITプロパートナーズ

週2〜3日から働ける柔軟な案件が業界トップクラスの豊富さを誇るフリーランスエージェント。エンド直契約のため高単価で、週3日稼働でも十分な報酬を得られます。リモートや時間フレキシブルな案件も多数。スタートアップ・ベンチャー中心で、トレンド技術を使った魅力的な案件が揃っています。専属エージェントが案件紹介から契約交渉までサポート。利用企業2,000社以上の実績。ITプロパートナーズ

Midworks 10,000件以上の案件を保有し、週3日〜・フルリモートなど柔軟な働き方に対応。高単価案件が豊富で、報酬保障制度(60%)や保険料負担(50%)など正社員並みの手厚い福利厚生が特徴。通勤交通費(月3万円)、スキルアップ費用(月1万円)の支給に加え、リロクラブ・freeeが無料利用可能。非公開案件80%以上、支払いサイト20日で安心して稼働できます。Midworks

らくらくPython塾 – 読むだけでマスター