📘

抽象クラスとインターフェースの違いからクラス設計を考えてみる。

2022/03/22に公開

目的

  • 抽象クラスとインターフェースの違いを理解する。
  • それぞれの特徴を理解したうえで、クラス設計を考えるときの武器とする。
  • あとがきが書きたくて。

対象読者

  • 抽象クラスとインターフェースの違いが分からない方
  • 抽象クラスとインターフェースを使いながら、クラスを設計する方法が分からない方

普段、アーキテクトとして活動している方にはツッコミどころが満載だと思う。
そういう方からのツッコミは、議論を洗練させていくためには必要不可欠なので、ぜひお願いしたい。

抽象クラスの特徴

  • 多重継承できない。(=子クラスは、抽象クラスを複数継承できない。)
  • プロパティ、メソッドを宣言できる。

インターフェースの特徴

  • 多重継承できる。(=子クラスは、複数のインターフェースを継承できる。)
  • メソッドだけ宣言できる。

抽象クラスとインターフェースの使い分け

実際に、Androidアプリ開発で利用する「RadioButtonクラス」を例に解説していく。
(※ViewクラスやTextViewクラス、Buttonクラス等には、クラス継承とは別にインターフェースが継承されてはいるが、今回は議論がややこしくなるので省いている。)

  • Viewクラス(通常クラス)
    • TextViewクラス(通常クラス)
      • Buttonクラス(通常クラス)
        • CompoundButtonクラス(抽象クラス)
          • RadioButtonクラス(通常クラス)
            となっている。
            ここで1つ抑えてほしいのは、親クラスの方にいけば、必ず抽象クラスやインターフェースとして定義されているわけでないということ。
            上に記載した抽象クラスとインターフェースの特徴を使い分けつつ、同類のものはクラス継承によって定義していくこと、別の部類だが同じ機能が必要なときはインターフェースとして切り出すのが大切な点であり、特段明確な答えがあるわけではないので、都度ホワイトボード等を使って議論していくことをオススメする。

もう少し身近な事例をもとに、自分なりのクラス設計について検討する。
ここでは題材として、動物の生態系を使う。

  • 動物クラス(抽象クラス)
    • 哺乳類クラス(抽象クラス)
      • 人間クラス(通常クラス):感情インターフェース継承
      • 犬クラス(通常クラス):感情インターフェース継承
    • 鳥類クラス(抽象クラス)
      • スズメクラス(通常クラス)
      • 鶏クラス(通常クラス)
  • 感情(インターフェース)

主な登場人物として、動物クラスを親としたクラス構成と、感情インターフェースがある。

まず、動物クラスについて考える。動物クラスの配下クラス(例:哺乳類クラスや鳥類クラスなど)で共通して持たせたいメソッドやプロパティが存在すると仮定し、特に動物クラス単体で利用する想定がない(=動物クラスの実態を必要としない)とき、動物クラスは抽象クラスとして定義する。

次に、哺乳類クラスを考えてみる。哺乳類クラスが単独で利用される想定があるときは、通常のクラス(=抽象クラスでもなく、インターフェースでもない。)として定義するが、通常のクラスとして定義すると、動物クラスで定義したものをオーバーライドすると同時に、哺乳類クラス単体で持つ必要があるメソッドやプロパティの「中身」を実装することができる。
ただ今回は、哺乳類クラスを単独で利用することは無いと仮定し、抽象クラスとする。
ここまで読んでわかるかも知れないが、実際の業務で必要な機能拡張と運用の観点を入れると、後々哺乳類クラスを単独で使いたいときに、抽象クラスとするのはリスクになる可能性がある。そうした場合には、哺乳類クラスを単独で利用するときに利用しそうなメソッドをインターフェースとして切り出しておいて、それを哺乳類クラスが継承し、哺乳類クラスは通常クラスとすることで、哺乳類クラスを柔軟なクラスとしておくこともあると思う。

次に人間クラスと犬クラスを考えてみる。
人間の下には、各個体しかいないと考えて、人間クラスの実態を生成したい(例えば、スズキさんを生成する)ので、人間クラスは通常クラスとすることが多いと思う。設計者によっては、人間クラスの下に、人種クラス等を作る人もいるかも知れないが、私としては人間クラスのプロパティに人種プロパティを持てば良いのでは?と思うので、人間クラスの下に人種クラスは作らない。加えて、そうした場合、人種別に異なる生態情報ってなんだろう?となり、多分、肌の色くらいなので冗長なクラス設計だと思うので、人種クラスは作らない。(あと、グローバルアプリを開発するときなどに、そんなクラスがあったら一発アウトだとも思うし、そろそろ怖いので話題を変えたい。笑)

犬クラスは、設計者によって分かれるところだと思う。
犬クラスの下に、犬種クラスを作成して、犬種ごとの特徴を保持する設計者と、犬種ごとの違いは、性格やサイズ程度だと仮定し、犬種クラスは冗長であり、犬種ごとの特徴は犬クラスにプロパティとして持てば良いのではないかと考える設計者もいると思う。
ここで大事なのは、実際の運用を考慮することなので、ステークホルダーの目線で少し考えてみる。

  • 実装者目線(=各プロダクトチームに所属するエンジニア)
    • 犬クラス、犬種クラスを利用するときに必要な情報はなにか?
    • 実際にどういう実装が多く、その実装が楽なのはどちらか?
  • 設計者目線(=基盤チームに所属するエンジニア)
    • 犬クラス、犬種クラスに対して、どういった拡張が考えられるか?
    • 今まで同じようなとき、どのように解決してきたか?

こうした情報を整理したうえで、どちらかを選択するべきか決める必要がある。繰り返しだが、一意となる答えはない。例えば、動物図鑑のアプリを作るような場合であれば、犬種クラスを作って拡張しやすい方が良いかも知れないし、ペットショップで利用されるアプリであれば、購入者は犬種による細かい違いより、犬ごとの性格やサイズ等の情報があれば十分なので、わざわざ犬種クラスを作らず、犬クラスだけで良いかもしれない。
といったように、具体的な状況に応じて、考える必要があるべきこと、そうでないこと(=冗長なこと)が変わってくる。

あとがき

今まで記載してきた内容を周囲の方に話すと、たまに「アーキテクチャ(MVVM等)が決まれば、クラス設計も自ずと決まるし、わざわざクラス設計を考える必要ある?」「クラス設計を考えるタイミングなんて業務しててある?」と聞かれたことがある。
はじめの頃は、何を質問されているのかわからなかったが、最近少しだけ分かってきた。(気がする。笑)
まず、質問者には色んなバックボーンの方がいる。

  1. 巨大なプロダクトがあり、基盤チームが存在し、それを利用したアプリ開発チームでしか開発経験が無い方
  2. マネージャーの方
  3. プロダクトに機能を追加し、ユーザーに届けることが好きで、設計等に関心が無い方

1.の方は、既に確立されているプロダクトチームに入っている事が多いので、機能強化をするときに、拡張したい機能があるべき場所(=クラス)を探して、そこに実装することが多く、特にクラス設計を意識しないで済んでいるのかなと思う。別に悪いことではなく、もしそのような環境で働いているエンジニアがいるとすれば、それは基盤チームが非常に優秀であり、プロダクト開発スピードも業界トップレベルな状態(=ビジネスも成功している可能性が大)だと推察されるので、自身を成長させる環境、安定して働ける環境として非常に魅力的だと思う。

2.の方は、今までのキャリアから触れる経験がないので、理解できるし、別に理解する必要があるとも思わない。というのも、昔、新しい基盤を構築するタイミングで、技術素養のあるマネージャーが必要だという結論になり、アーキテクトからマネージャーになった方がいた。その方のもとで、アーキテクチャ設計ができる技術者数名と数名のジュニア・シニア技術者のいるチームができた。ある程度、アーキテクトとしても経験があるマネージャーが設計に口出しをするようになり、アーキテクトとよく意見が衝突していた。というのも、設計というのは一意となる答えがあるわけではないので、性格や好み、環境に左右されることが否めない。マネージャーは他チームと折衝交渉したり、社長や技術部長等に説明責任があるので、自分の見立てが立てやすいような設計をしてほしいときもある。アーキテクトは、世の中で出回っている新しい設計思想を取り入れながら、自分が今まで気になっていた部分を解決することに注力したくなる。そういうものだ。あまり詳細には書けないが、こうした経験から、職責に応じて役割分担するというのは理想だが、現実そう上手くいかないとも思うので、マネージャーとしてのキャリアを積んでいる方が、わざわざ理解する必要は無いのではと思うに至っている。

3.組織が小さい場合だと難しいかも知れないが、組織が大きくなると設計に関心が無い方も必ず必要になるので、理解できる。こういう人が、各プロダクトチームにいると、カスタマーサポートやセールス、マーケ、BizDevとの連携が活発になるし、何よりユーザーが喜ぶことを知っている事が多い。設計が得意で好きな人が、ユーザーに価値を届けるのが好きな人だとは限らないし、(総じてそうでないことのほうが多い気がするので)事業を伸ばすためにも必要不可欠だと思う。ちなみに、そうした人は、あんまりAtCoderとかに関心は無いが、他所のアプリで新しくリリースされた機能などに詳しく、テンション高めの人が多いイメージがある。

締め方が難しいが、、、
いずれにしても、エンジニアならこのくらいは理解すべきというのは、会社やチーム等によって変わるので、その都度柔軟に対応できればいいと思う。クラス設計もしかり。
クラス設計について考えたくなったとき、この記事が皆さんの一助になれば嬉しい。

Discussion