抽象クラスって聞いたことあるけど、いまいちメリットとか使い道が理解できていなかったので、整理しました!
本記事は、以下のような方を対象にしています。
- 抽象クラス(Abstract)?何それって方
- 抽象クラス(Abstract)は聞いたことあるけど、使ったことないなあって方
それでは行きしょう!!
そもそも抽象クラス / メソッドって?
抽象クラスは、抽象メソッドを1つ以上持ちます。
1 2 3 |
abstract class クラス名{ 抽象メソッド } |
抽象メソッドは、以下の形式で記述されます。
1 2 3 |
abstract class クラス名{ abstract 戻り値の型 メソッド名(引数の型 引数); } |
クラス名 / メソッド名の前に abstract を記述するだけで、抽象クラス / メソッドが作成できます。
抽象メソッドには具体的な実装を持ちません。
じゃあ、抽象クラスを作成する意図は?
抽象クラスとは一言で言えば、クラスの規約や雛型です。
抽象クラスには処理を記述しません。
処理の大枠(規約)を記載して、そのクラスを継承したサブクラスで実際の処理の中身を記述します。
抽象クラス自体は意味がなく、継承して初めて意味を持ちます。
抽象クラスで作成した抽象メソッドは、サブクラスでオーバーライドする必要があります。
オーバーライドしなかった場合、ビルドエラーとなります。
意図は理解できたけど、メリットはあるの?
自分だけで実装する場合は、メリットはほぼないです。
しかし、複数人で実装する場合は、メリットがあります。
前項で説明した通り、抽象メソッドはサブクラスで必ずオーバーライドする制約があります。
この制約は、
複数人で開発を行う場合に実装レベルのルールを作れる
ということを意味します。
例として、あるシステムに帳票出力機能の追加対応を複数人で分担して行う場合を考えます。
帳票 01 ~ 03 の3帳票を追加し、帳票ごとにクラスを作成するとします。
この場合は3クラス必要ですが、Aさん、Bさん、Cさんの3名に1クラスずつ作成してもらうことにしました。
3名とも実装完了したので確認してみると、メソッド名・プロパティ名がそれぞれ違う!!
・・・というようなことが往々にして発生すると思います。
同じ処理なのにメソッド名・プロパティ名が統一されていないと、他メンバーが見た時に理解に時間が掛ってしまいますね。
ここで、抽象クラスの出番です!
初めに抽象クラスを作成して、AさんBさんCさんはその抽象クラスを継承することで、
オーバーライドが強制されるのでメソッド名・プロパティ名・処理の流れまでも統一することができます!
それでは今回のケースのサンプルプログラムを紹介します!
サンプルプログラム
以下が抽象クラスです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
using System; using System.Collections.Generic; using System.Data; using System.Web; using GrapeCity.ActiveReports.Export.Pdf.Section; using GrapeCity.ActiveReports; namespace Report { /// <summary> /// 各帳票固有の情報を保持するクラスの基本クラス /// </summary> internal abstract class ReportBase { /// <summary> /// コンストラクタ /// </summary> internal ReportBase() { } #region Fields /// <summary> /// 帳票種別 /// </summary> internal abstract ReportId ReportId { get; set; } /// <summary> /// 帳票レイアウトファイル名 /// </summary> internal abstract string LayoutFile { get; set; } #endregion #region Methods /// <summary> /// セクションレポートを生成する。 /// </summary> /// <returns>SectionReportオブジェクト</returns> internal abstract SectionReport CreateSectionReport(); #endregion } } |
以下が抽象クラスを継承したサブクラスです。
抽象メソッドをオーバーライドして具体的な処理を実装しています。
このクラスを使い回せば帳票クラスを容易に複製できますね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
using System; using System.Data; using GrapeCity.ActiveReports.Export.Pdf.Section; using GrapeCity.ActiveReports; namespace Report { /// <summary> /// 帳票01のデータを持つクラス /// </summary> internal class Report_01 : ReportBase { /// <summary> /// 帳票種別 /// </summary> internal override ReportId ReportId { get; set; } = ReportId.Report_01; /// <summary> /// 帳票レイアウトファイル名 /// </summary> internal override string LayoutFile { get; set; } = "Report_01.rpx"; /// <summary> /// コンストラクタ /// </summary> /// <param name="parameters"></param> internal Report_01() : base() { } /// <summary> /// セクションレポートのインスタンスを作成し、 /// 帳票設定を行う。 /// </summary> /// <returns>セクションレポート</returns> internal override SectionReport CreateSectionReport() { SectionReport rpt = new SectionReport(); // 用紙サイズ:A4 rpt.PageSettings.PaperKind = System.Drawing.Printing.PaperKind.A4; // 用紙向き:横 rpt.PageSettings.Orientation = GrapeCity.ActiveReports.Document.Section.PageOrientation.Landscape; return rpt; } } } |
まとめ
今回は抽象クラスについてまとめました。
抽象クラス / メソッドの使い道やメリットが伝わりましたでしょうか?
抽象クラスは単純に1クラス分コード量が増えるので無闇に使えばよいわけではありません。
適切に使えばプログラムに制約を持たせて、統一性・可読性を向上させることができます。
今回は以上です。それでは!!