C#初心者のための基礎!ポリモーフィズムと抽象クラスの使い方を解説#29

当サイトではアフィリエイト広告を利用しています。

C#初級プログラミング

抽象クラスとは?

抽象クラスとは、インタフェースとほとんど同じような効果を発揮しますが、異なる点は、ロジックが書けるという点です。インタフェースは定義しか書けないのに対して、抽象クラスはロジックが書けるため、ロジックの途中で部分的に抽象クラスのメソッドに切り替えることができます。このような書き方をデザインパターンのテンプレートパターンといいます。

抽象クラスの書き方

抽象クラスの書き方は、アクセス修飾子、abstractキーワード、classキーワード、任意のクラス名の順に書きます。抽象クラスを継承するサブクラス側は、通常の継承のときと同じ書き方になるので、サブクラスのクラス名の後にコロンでつないで抽象クラス名を記述します。

抽象メソッドとは?

抽象メソッドとは、派生クラスに実装を強制するメソッドになります。抽象クラスは普通のクラスのように記述できますが、派生クラスに処理をゆだねる場合は、メソッドにabstractキーワードを付けて、派生クラスに実装を強制できます。

サンプルコード

抽象クラスはabstractキーワードを使います。インタフェースではSaveメソッドのみを強制するという感じですが、抽象クラスはSaveクラスに共通部分のロジックを記述し、共通にできない部分のみを派生クラスに委ねます。この場合、トランザクションやコミット、ロールバック処理は共通ですが、Save処理は各派生クラスごとに、登録するテーブルが異なるため、この部分だけSaveMethodで派生クラスに実装を強制しています。派生クラスに実装を強制する場合はメソッドにabstractキーワードを付けます。

namespace CS29
{
    public abstract class DataBase
    {
        public void Save()
        {
            try
            {
                Transaction();

                SaveMethod(); //ここが虫食い状態(派生クラスごとに処理が違う)

                Commit();
            }
            catch
            {
                RollBack();
            }
        }

        protected abstract void SaveMethod();

        private void Transaction()
        {
        }

        private void Commit()
        {
        }

        private void RollBack()
        {
        }
    }
}

派生クラスは、抽象クラスのabstractメソッドをoverrideキーワードを用いて実装しておかないとコンパイルエラーとなります。

namespace CS29
{
    class Products : Database
    {
        protected override void SaveMethod()
        {
            Console.WriteLine("商品マスタの登録");
        }
    }
}
namespace CS29
{
    class Orders : Database
    {
        protected override void SaveMethod()
        {
            Console.WriteLine("発注テーブル登録");
        }
    }
}
namespace CS29
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            Database product = new Products();
            Database orders = new Orders();

            List databases = new List();
            databases.Add(product);
            databases.Add(orders);

            foreach (var val in databases)
            {
                val.Save();
            }
        }
    }
}

クライアントコードでの実装はインタフェースのときと何ら変わりません。val.Save()の部分で抽象クラスの場合はトランザクション処理等が共通で行われていますが、特に意識せず、クライアントコードからは呼び出しを行うことができます。