ユーザー定義型に対して、
構成(Composition),
集約(Aggregation),
継承(Inheritance) を適切な選択します。
序文:
複合型構造は、構成、集約、継承 を通して構築できます。
構成と集約(関連付け(association)の特殊な形式)は、単純なものから、より複雑な型を作成するプロセスです。
継承は、既存のものの属性と動作を取得することにより、より複雑な型を作成するプロセスです。
「継承よりも構成を優先する」、または「コードを再利用するためだけに、継承を使わない」という、非常に有名な設計原則があります。
FreeBASIC での合成を支持するもう1つの理由は、他の多くの言語と同様、多重継承をサポートしていないことです。
構成、集約、継承の定義
使用する関係の形式の選択を尋ねる適切な質問は、アプリケーションの存続期間を通じて、この関係が
"HAS-A" か
"USES-A" か
"IS-A" であるかどうかを判断することです(以下の例を参照)。
ユーザーが、型のプロパティと動作を、その型内で変更せずに使う必要がある場合、関連付け(association)が、より良いオプションです。
一方、ユーザー型内の型のプロパティと動作を使用して変更する必要がある場合は、継承を使うのが最適です。
各関係の定義
構成(強力な関連付け(association))は、オブジェクト間に
"HAS-A" 関係を確立します:
- 構成では、コンポーネント・オブジェクトは、その複合オブジェクトを使用するためだけに存在します。
- 複合オブジェクトが破棄されると、コンポーネント・オブジェクトも破棄されます:
- オブジェクト の構成の
型 に追加する、メンバー項目の構文(または同様の構文):
objectname As objecttypename [= initializer]
集約(弱い関連付け(association))は、オブジェクト間の
“USES-A” 関係を確立します:
- 集約では、コンポーネント・オブジェクトは、集約オブジェクトでの使用とは無関係に存在できます。
- 集約を破棄しても、コンポーネントは破棄されません:
> 型には、オブジェクトへのポインタのみが含まれるため。
- オブジェクト の集約の
型 に追加する、メンバー項目の構文(または同様の構文):
objectptrname As objecttypename Ptr [= initializer]
継承により、インスタンス化可能な型間の
“IS-A” 関係が確立されます:
- 派生型には、基本型と同じ特徴と機能がありますが、いくつかの拡張があります。
- オブジェクトの継承のための、
型の宣言ヘッダーの構文:
継承を超える、オブジェクトの関連付け(構成/集約)の利点
ほとんどの場合、 "HAS-A" や "USES-A" の関係は、"IS-A" の関係よりも意味的に正しいものです。
集約は、継承よりも柔軟です。
型の実装は、実行時にコンポーネント・オブジェクトを変更することで、変更できますが、これは継承ではできません(基本型の動作は実行時に変更できません)。
オブジェクトの関連付けに基づいたデザインの型は、通常、少なくなります。
複数のオブジェクトを1つに構成することで、疑似「多重継承」を(これをサポートしない言語で)実装することができます。
手続き名とプロパティ名の間に競合はありません。これは継承によって発生する可能性があります。
継承と比較した、オブジェクトの関連付け(構成/集約)の欠点
集約を使うと、ソースコードを見るだけでは、システムの動作を、理解するのが難しくなる可能性があります。
これは、コンパイル時ではなく、実行時に、型間で、より動的で相互作用が発生するためです。
アソシエーション・アプローチでは、より多くのコードと時間が必要になる場合があります。
オブジェクトの関連付けに基づくデザインには、通常、より多くのオブジェクトが含まれます。
例
構成、集約、継承を組み合わせた、簡単な実例:
' Between the different types "Driver", "Person", "Driver_license" and "Vehicle", the respective relationships are:
' - A driver “IS-A” person (driver is a person): => "INHERITANCE".
' - A driver “HAS-A” driver's license (driver license only existing for the driver): => "COMPOSITION".
' - A driver “USES-A” vehicle (vehicle lifetime independent of the driver life): => "AGGREGATION".
Type Person
Public:
Dim As String full_name
Declare Constructor (ByRef _full_name As String)
Protected: '' to forbid at compile time the default-construction attempt of a Person instance
Declare Constructor ()
End Type
Constructor Person (ByRef _full_name As String)
This.full_name = _full_name
End Constructor
Type Driver_license
Public:
Dim As Integer number
End Type
Type Vehicle
Public:
Dim As String registration
Declare Constructor (ByRef _registration As String)
End Type
Constructor Vehicle (ByRef _registration As String)
This.registration = _registration
End Constructor
Type Driver Extends Person '' inheritance
Public:
Dim As Driver_license dl '' composition
Dim As Vehicle Ptr pv '' aggregation
Declare Constructor (ByRef _full_name As String, ByRef _dl As Driver_license)
End Type
Constructor Driver (ByRef _full_name As String, ByRef _dl As Driver_license)
Base(_full_name)
This.dl = _dl
End Constructor
Dim As Driver d1 = Driver("User fxm", Type<Driver_license>(123456789))
Dim As Vehicle Ptr pv1 = New Vehicle("ABCDEFGHI")
d1.pv = pv1
Print "Person full name : " & d1.full_name
Print "Driver license number : " & d1.dl.number
Print "Vehicle registration : " & d1.pv->registration
Delete pv1
d1.pv = 0
Sleep
出力:
Person full name : User fxm
Driver license number : 123456789
Vehicle registration : ABCDEFGHI
参照