Midoliy |> F# - 抽象クラス
抽象クラス
Midoliy|F#プログラミング
抽象クラスの概要
サンプルでみる抽象クラス

抽象クラスの概要


 抽象クラス(= abstract class)は、一部またはすべてのメンバを未実装のままにするクラスです。そのため、実装は派生クラスによって提供することができます。抽象クラスはインターフェースと同様、OOP世界の考え方です。そして、提供している機能に関してはインターフェースとかなり似ています。インターフェースとはどう違うのでしょうか?
 インターフェースが「実装したクラスが共通して持っている能力」を定義していることに対して、抽象クラスは「派生クラスならば当然持っている能力」を定義しているところに差があります。つまり、抽象クラスはクラスの親子関係に重きを置く考え方ということです。反対に、インターフェースはクラス同士の関係には興味がありません。その処理を行えるか行えないかだけに興味があります。
 上記の内容は非常に難しい考えのため、今は読み飛ばしてしまって構いません。別記事にて詳細な説明をしようと思います。

 以下は抽象クラスの構文になります。
// ------------------
// [ 構文 ]
// ------------------
[<AbstractClass>]
type [ accessibility-modifier ] abstract-class-name =
    [ inherit base-class-or-interface-name ]
    [ member-definitions ]
    [ abstract-member-definitions ]

    // 抽象メンバの定義方法
    abstract member member-name : type-signature
                

 構文を見てもらうとわかるとおり、インターフェースとは違い、抽象クラスには抽象メンバ以外にも普通のメンバを定義することが可能です。


 サンプルを見ていただくとわかるとおり、抽象クラスを直接インスタンス化することは許されていません。これは、"抽象"という名称からもわかるとおり、具体的なものではないために実体化(= インスタンス化)できないわけです。これはインターフェースにも同じことが言えます。また、抽象クラスから派生したクラス(= 派生クラス)で、抽象メソッドや抽象プロパティを実装する場合には overrideキーワード を付ける必要がありますので注意しましょう。
 インターフェースやクラス、構造体とは違い抽象クラスには冗語構文はなく、また、必ず[<AbstractClass>]属性を付けなければならないことにも注意が必要です。


サンプルでみる抽象クラス


 前節で抽象クラスの簡単な構文を紹介しました。本節では簡易的なサンプルを利用して、実際の値と構文の説明がどう対応しているかを見ていきたいと思います。今回のサンプルは前節と同様の Shape2D型 を利用していきたいと思います。
 繰り返しとなりますが、下記は Shape2D型 の定義となります。


 下記の表は内包している要素と構文の要素名とを対応付けたものとなります。ただし重複する内容のものに関しては省略しています。
 また、改めて抽象クラスの宣言構文も記載しています。

// ------------------
// [ 構文 ]
// ------------------
[<AbstractClass>]
type abstract-class-name =
    [ member-definitions ]
    [ abstract-member-definitions ]

    // 抽象メンバの定義方法
    abstract member member-name : type-signature
                

要素名 対応するShape2D型の要素
abstract-class-name Shape2D
member-definitions mutable x, y
abstract member member-name : type-signature Area : float with get
Name : string with get
Rotate : float -> unit

 抽象クラスは抽象メンバの宣言とクラス宣言が入り混じるため、実際の宣言をみると構文より複雑に感じると思います。しかし、実際はインターフェースとそこまで複雑さは変わりません。
 最初に [<AbstractClass>]属性 を付与した type を宣言します。そして [ abstract-class-name ] を指定して、派生クラスに実装してもらいたいメンバを宣言すればよいわけです。

 抽象クラスは機能としては存在しますが、個人的には使用することをあまりオススメしません。これは継承問題の話もありますが、クラスの継承機能をよくわからないまま利用するとコードの可読性に深刻な影響を与えます。使うタイミングや状況を正しく見極められるようになるまでは極力使用しないようにしましょう。