基本クラスの使用方法のガイドライン
クラスは、最も一般的な種類の型です。クラスには、抽象クラスとシール クラスがあります。抽象クラスの実装を提供するには、派生クラスが必要です。シール クラスの派生クラスは作成できません。クラスは、別の型の上位で使用することをお勧めします。
基本クラスは、一般的な一連の機能を共有するオブジェクトをグループ化するために役立ちます。基本クラスによって一連の既定の機能を提供でき、基本クラスを拡張することによってそれらの機能をカスタマイズすることもできます。
クラスには明示的にコンストラクタを提供する必要があります。一般的に、コンストラクタを定義していないクラスには、コンパイラによりパブリックの既定のコンストラクタが追加されます。目的がクラスを作成できないようにすることであれば、この方法はユーザーに誤解を与えます。したがって、クラスには常に少なくとも 1 つのコンストラクタを定義することが最良の方法です。クラスを作成できないようにする場合は、コンストラクタをプライベートにします。
デザインに機能拡張やポリモーフィズムを追加するのは、その必要があることが明らかな場合に限ります。たとえば、データアダプタ用のインターフェイスを提供することは難しく、実際にはあまり利点がありません。インターフェイスを提供しても、開発者は依然としてアダプタごとに固有のコードをプログラミングする必要があるため、それほど利点はありません。しかし、すべてのアダプタ間で一貫性をサポートする必要はあります。この場合、インターフェイスまたは抽象クラスを提供することは適切ではありませんが、一貫性のあるパターンを提供することはとても重要です。このような一貫性のあるパターンを開発者に提供するには、基本クラスを使用します。基本クラスを作成するときは、次のガイドラインに準拠します。
基本クラスとインターフェイス
インターフェイス型は、プロトコルの仕様であり、多くのオブジェクト型でサポートされる可能性があります。可能な限り、インターフェイスではなく基本クラスを使用してください。バージョン管理という点では、クラスの方がインターフェイスよりも柔軟性があります。クラスを使用した場合、バージョン 1.0 を出荷した後で、バージョン 2.0 で新しいメソッドをそのクラスに追加できます。追加するメソッドが抽象メソッドでない限り、既存の派生クラスは変更しなくても機能します。
インターフェイスは実装の継承をサポートしないため、クラスに適用されるパターンがインターフェイスには適用されません。インターフェイスにメソッドを追加することは、基本クラスに抽象メソッドを追加することに等しく、この場合、インターフェイスを実装するすべてのクラスは、新しいメソッドを実装しないため破損してしまいます。
インターフェイスは、次の場合に適しています。
- 関連していない複数のクラスで同じプロトコルをサポートする場合。
- それらのクラスが既に基本クラスを確立している場合 (ユーザー インターフェイス (UI) コントロール、XML Web サービスなど)。
- 集約が適切ではない、または現実的ではない場合。
それ以外の場合は、クラスの継承の方が優れたモデルです。
プロテクト メソッドおよびコンストラクタ
プロテクト メソッドを用意することにより、クラスをカスタマイズできるようにしておきます。基本クラスのパブリック インターフェイスは、そのクラスのコンシューマが使用できる豊富な機能を提供する必要があります。しかし、クラスを使用する開発者は、実装するメソッドの数はできるだけ少なく抑えながら、コンシューマには豊富な機能を提供しようと考えます。この要件を満たすには、非仮想または最終的なパブリック メソッドを提供し、これらのメソッドから、それぞれの実装を提供する単一のプロテクト メソッドが呼び出されるようにします。このメソッドは、Impl
サフィックスでマークする必要があります。このパターンを使用することを、テンプレート メソッドを提供する、とも言います。この処理を行うコード例を次に示します。
Public Class SampleClass
Private x As Integer
Private y As Integer
Private width As Integer
Private height As Integer
Private specified As BoundsSpecified
Overloads Public Sub SetBounds(x As Integer, y As Integer, width As
Integer, height As Integer)
SetBoundsImpl(x, y, width, height, Me.specified)
End Sub
Overloads Public Sub SetBounds(x As Integer, y As Integer, width As
Integer, height As Integer, specified As BoundsSpecified)
SetBoundsImpl(x, y, width, height, specified)
End Sub
Protected Overridable Sub SetBoundsImpl(x As Integer, y As Integer,
width As Integer, height As Integer,
specified As BoundsSpecified)
' Insert code to perform meaningful operations here.
Me.x = x
Me.y = y
Me.width = width
Me.height = height
Me.specified = specified
Console.WriteLine("x {0}, y {1}, width {2}, height {3}, bounds {4}",
Me.x, Me.y, Me.width, Me.height, Me.specified)
End Sub
End Class
[C#]
public class MyClass
{
private int x;
private int y;
private int width;
private int height;
BoundsSpecified specified;
public void SetBounds(int x, int y, int width, int height)
{
SetBoundsImpl(x, y, width, height, this.specified);
}
public void SetBounds(int x, int y, int width, int height,
BoundsSpecified specified)
{
SetBoundsImpl(x, y, width, height, specified);
}
protected virtual void SetBoundsImpl(int x, int y, int width, int
height, BoundsSpecified specified)
{
// Add code to perform meaningful opertions here.
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.specified = specified;
}
}
多くのコンパイラ (C# コンパイラなど) では、public コンストラクタまたは protected コンストラクタがない場合、それらが自動的に挿入されます。そのため、ソース コードの体裁を整え、読みやすくするには、すべての抽象クラスで明示的に protected コンストラクタを定義する必要があります。
シール クラスの使用方法のガイドライン
クラスが静的メソッドと静的プロパティしか持たない場合は、シール クラスを使用します。
参照
クラス ライブラリ開発者向けのデザイン ガイドライン | 型の使用方法のガイドライン | クラスの名前付けのガイドライン