

タイトルの文面がどこで得た情報なのかが記憶が定かではないのですが、C#において、抽象クラスにはなるべく実装メソッドは書くべきではないと見聞きしたような覚えがあります。

しかし、上文の通り、どこで得た情報なのかが定かではなく、故に記憶違いの可能性もあり正しい知識なのか不安になったため、ここで質問させていただきます。

Webで調べてみても、解説しているコードの抽象クラス内に「抽象メソッド」と「実装されているメソッド」が混在しており、「タイトルの内容は間違いでは？」と半ば結論付けてはいるのですが、確信があるわけではありません。

参考までに、現在私が直面しているコードの内容を簡潔に一例として挙げさせていただきます。

【参考内容】  
※実装されているメソッドを「実装メソッド」と呼称します。

  * 抽象クラスHogeBaseクラス内に、抽象メソッドHogeCalc、実装メソッドHogeDrawがある
  * HogeBaseクラスを基底クラスとし、複数の派生クラスを作成する。
  * HogeManagerクラスは作成した各派生クラスのHogeDrawを呼ぶ。この時、派生クラスではHogeCalcを実装。その他の必要な初期化以外の記述は行わない。
  * 派生クラス全てに共通した変数の初期化や計算、インスタンスの生成等はHogeBaseクラスで行う。

特に、この「派生クラス全てに共通した変数の初期化や計算、インスタンスの生成等はHogeBaseクラスで行う。」において、共通しているから基底クラスで実装しているものの「あくまで基底なんだからそこで初期化とか計算とか行うべきではない？」と考えてしまい、これがタイトルの内容につながっています。

長文になってしまい申し訳ありません。  
何卒、正誤のご教授の方、よろしくお願いいたします。


CC BY-SA 4.0
2018-07-24T09:28:55.527
46907
2023-05-07T12:43:32.747
2018-07-24T09:47:42.383
19110
20642
question
c#
抽象クラスにはなるべく実装メソッドはない方が良い？


「実装メソッド」を一つも持たない型はC#では抽象クラスとは別の存在[`interface`](https://docs.microsoft.com/ja-
jp/dotnet/csharp/programming-
guide/interfaces/)となります。ですので「抽象クラスにはなるべく実装メソッドはない方が良い？」が真だとするとそれは抽象クラスではなくなるため正しくないと思います。

また、例えば全てのストリームの基底となる[`System.IO.Stream`](https://msdn.microsoft.com/ja-
jp/library/system.io.stream\(v=vs.110\).aspx)は`IStream`のような`interface`とはされておらず抽象クラスとされ、また多数の「実装メソッド」を持っています。この設計に倣うのであれば抽象クラスは実装メソッドを大いに持つべきです。

これらはあくまでC#言語における設計であり、他の言語ではまた事情が異なってきます。

* * *

上で紹介した`interface`ですが、C#
8.0からは[既定のインターフェイスメンバー](https://learn.microsoft.com/ja-
jp/dotnet/csharp/language-reference/keywords/interface#default-interface-
members)を持てるようになりました。つまり抽象クラスだけでなく`interface`であっても、必要であれば実装メソッドを持つことが許されます。わざわざこのような機能拡張が行われたのはもちろん実装メソッドを持つべきという思想からでしょう。


CC BY-SA 4.0
2018-07-24T09:52:23.420
46909
2023-05-07T12:43:32.747
2023-05-07T12:43:32.747
4236
4236
46907
answer


そもそもオブジェクト指向において継承はコードの共通化という目的のために存在していると思います。  
コードの共通化という目的を満たさないのであれば、継承階層を構築してしまうというデメリットを支払えないと思います、抽象メソッドができることはシグニチャを縛ることでこれはコード量の削減には一切寄与しません。コードの共通化を行えるのは実装メソッドのみです。

設問者が提示する話ですが、処理の共通部を担うクラスHogeDrawへのインスタンスへの参照を保持し、処理の差分部をインターフェースIHogeCalcの実装とすれば、継承階層をなくすことができます。(いわゆる継承を使わず、コンポジションでの代用を試みるという設計原則)  
ここで重要なのがHogeDrawとHogeCalcの役割分担です。HogeDrawがクラスに関わらず不変となるようにCalcとの役割分担ができるのであれば、上記のような継承階層をなくすことが可能ですが、そうでない場合はおそらく継承を使うほうがいいのでしょう。  
(継承を回避したいのは、C#がクラスの多重継承を認めないため、ある観点でのクラス階層を構築してしまうとある観点において階層を再構築しようとしてもうまくいかないから、現代的なオブジェクト指向は抽象クラスの継承よりもinterfaceによるmixinを推奨しているというのが主流であると私は考えています)


CC BY-SA 4.0
2018-07-29T16:54:09.527
47082
2018-07-29T16:54:09.527
25980
46907
answer