VB.Net中文教程(4) 類別繼承(Inheritance)關係 (轉)

worldblog發表於2007-12-06
VB.Net中文教程(4) 類別繼承(Inheritance)關係 (轉)[@more@]

請注意 ......
著作權所有人:物澤事業股份有限公司、
  MISOO技術顧問團隊、物件導向雜誌作者、等。
u本摘自 物件導向雜誌、精通物件觀念與技術等書籍著作。
u本檔案僅供您的參閱,請遵守著作權法,不得做其它商業用途。


  主題:  類別繼承(Inheritance)關係


??????????  內容  ??????????
v 1. 定類別之繼承
v 2. 定義繼承關係
v 3. 藉「繼承」擴充

 


1. 類別之繼承

  類別之間﹐有些互為獨立﹐有些具有密切關係。茲介紹類別間常見的關係──「父子」關係﹔由於兒女常繼承父母之生理或心理特徵﹐所以又稱此關係為「繼承」(Inheritance) 關係。類別間之密切關係﹐把相關的類別組織起來﹐並且組織程式內之物件。若程式內之物件毫無組織﹔呈現一片散沙﹐就不是好程式。完美之VB程式﹐必須重視類別間之關係﹐物件是有組織的。
  如果 A類別「繼承」 B類別﹐則稱 A為「子類別」(Subclass)﹐也稱B 為「父類別」(Superclass)﹐亦即 B為 A之父類別﹐A 為 B之子類別。在 C++中﹐父類別又稱為「基礎類別」(Base Class)﹐子類別又稱為「衍生類別」(Derived Class) 。也許您覺得「繼承」之觀念很陌生﹐不知如何看出類別間之繼承關係。別擔心﹐有個簡單方法﹕下列兩敘述之意義相同──
  (1) A 為 B之子類別。
  (2) A 為 B之一種(A kind of) 特殊類別。

根據敘述 (2)能輕易找到父子關係。例如﹕肯尼士(Kennex)生產高品質球拍﹐球拍分兩種﹕網球拍與羽球拍。從此句子得知﹕網球拍為一種(A kind of) 球拍﹐羽球拍亦為一種球拍。因之﹐網球拍為球拍之子類別﹐羽球拍亦為球拍之子類別﹐亦即球拍是父類別。以下圖示之﹕

 
  圖1、 基礎類別與衍生類別

  如果設計程式來記錄球拍之生產情形﹐則程式應定義基礎類別──球拍﹐以及兩衍生類別──網球拍及羽球拍。程式應藉繼承關係將三類別組織起來。除了物品(如球拍、汽車等)外﹐人也有繼承關係。例如﹕學校人員包括學生、老師及職員﹐老師又分為專任老師及兼任老師。學校的人事﹐應定義類別關係如下﹕
 
  圖2、 三代繼承關係

  程式不僅要定義類別﹐也要定義其繼承關係。

 

2. 定義繼承關係

  前面各章裡﹐已介紹如何定義類別﹔本節將告訴您如何定義類
別之繼承關係。茲舉例說明之﹕

 

程式的設計過程是﹕
  step 1. 定義基礎類別(父類別)。如﹕

  Class Person
  ‥‥
  End Class

  step 2. 定義衍生類別(子類別)。如﹕

  Class Teacher
  Inherits Person
  ‥‥
  End Class
  Class Student
  Inherits Person
  ‥‥
  End Class

  Inherits字眼之後為父類別名稱。它表達了:Teacher 為Person之子類別﹐且 Student為Person之子類別。現在﹐已知道如何表達繼承關係了﹔然而﹐子類別從父類別繼承什麼東西呢﹖類別包含「資料」及「程式」。因之﹐子類別繼承父類別之資料及程式。現在﹐請看看如何繼承資料及程式。下述程式定義 Person 類別﹐含有 2項資料及 3個程式﹕

'ex01.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.s
'-----------------------------------------------------------------------------------------
Class Person
  Private name As String
  Private age As Integer
  Public Sub SetValue(ByVal na As String, ByVal a As Integer)
  name = na
  age = a
  End Sub
  Public Function birthYear() As Integer
  birthYear = 2001 - age
  End Function
  Public Sub Display()
  Messagebox.Show("Name: " + name + "  Age: " + str(age))
  End Sub
End Class
'-----------------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win FoDesigner.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrs dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Form Designer generated code "
  .......
#End Region
  Protected Sub Form1_Click( ByVal sender As , ByVal
  e As System.EventArgs)
  Dim mike As Person
  mike = New Person()
  mike.SetValue("Mike", 45)
  mike.Display()
  Messagebox.Show("BirthYear: " + Str(mike.birthYear()))
  End Sub
End Class

此程式輸出如下﹕ 
Name: Mike  Age: 45
BirthYear: 1956


  所謂繼承資料﹐表示繼承資料成員之定義﹐而不是繼承資料之值﹐請詳加區別之。類別定義資料成員(含型態及名稱)﹐物件誕生後﹐物件內才有資料值。所以「類別繼承」乃繼承類別之定義﹐不是繼承物件之值。也就是說﹕若父類別定義name及 age兩個資料成員﹐則子類別天生就擁有此兩個資料成員﹐所以子類別不需定義它們。所謂繼承程式﹐表示子類別天生就擁有父類別定義之程式成員。例如﹕Person的子類別天生就具有 SetValue()、birthYear()及Display()程式。現在﹐就來定義Person之子類別。

'ex02.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'-----------------------------------------------------------------------------------------
Public Class Person
  Private name As String
  Private age As Integer
  Public Sub SetValue(ByVal na As String, ByVal a As Integer)
  name = na
  age = a
  End Sub
  Public Function birthYear() As Integer
  birthYear = 2001 - age
  End Function
  Public Sub Display()
  Messagebox.Show("Name: " + name + "  Age: " + str(age))
  End Sub
End Class

Public Class Teacher
  Inherits Person
 
End Class
'-----------------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Windows Form Designer generated code "
  .......
#End Region
  Protected Sub Form1_Click( ByVal sender As Object, ByVal
  e As System.EventArgs)
  Dim steven As Teacher
  steven = New Teacher()
  steven.SetValue("Steven", 35)
  steven.Display()
  End Sub
End Class

此程式輸出如下﹕
  Name: Steven  Age: 35

  表面上Teacher 類別中﹐未定義資料項及程式﹐但事實上已擁有name及 age兩個資料成員﹐也擁有 SetValue()、birthYear()及Display() 三個程式成員。因之﹐steven為Teacher類別之物件﹐它能呼叫SetValue()及Display()程式。在應用上﹐子類別通常擁有自己的資料項及程式﹐使其有別於父類別。例如﹕

'ex03.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'------------------------------------------------------------------------------------------------------
Public Class Person
  Private name As String
  Private age As Integer
  Public Sub SetValue(ByVal na As String, ByVal a As Integer)
  name = na
  age = a
  End Sub
  Public Function birthYear() As Integer
  birthYear = 2001 - age
  End Function
  Public Sub Display()
  Messagebox.Show("Name: " + name + "  Age: " + str(age))
  End Sub
End Class

Public Class Teacher
  Inherits Person
 
  Private salary As Decimal
  Public Sub tr_SetValue( ByVal na As String, ByVal a As Integer, ByVal
  sa As Decimal)
  SetValue(na, a)
  salary = sa
  End Sub
  Public Sub pr()
  MyBase.Display()
  Messagebox.Show("Salary: " + str(salary))
  End Sub
End Class
'-----------------------------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Windows Form Designer generated code "
  ........
#End Region
  Protected Sub Form1_Click( ByVal sender As Object, ByVal
  e As System.EventArgs)
  Dim steven As Teacher
  steven = New Teacher()
  steven.tr_SetValue("Steven", 35, 35000)
  steven.pr()
  End Sub
End Class

此程式輸出如下﹕
Name: Steven  Age: 35
Salary: 35000

現在﹐Teacher 類別含有三個資料成員﹕
  1. name ──從Person類別繼承而來。
  2. age ──從Person類別繼承而來。
  3. salary ──自己定義的。

此外﹐也含有五個程式成員﹕
  1. SetValue() ──從Person繼承而來。
  2. birthYear()──從Person繼承而來。
  3. Display() ──從Person繼承而來。
  4. tr_SetValue()──自己定義的。
  5. pr()──自己定義的。

  由於SetValue()為 Teacher之程式成員﹐所以tr_SetValue()能直接呼叫SetValue()來設定name及age值﹔之後﹐tr_SetValue()自己設定salary之值。同理﹐pr()能直接呼叫 Display()來顯示name及age之內容﹔之後﹐pr()自己輸出salary之值。也許﹐您會問道﹕子類別自己定義之程式﹐是否能與父類別之程式同名稱呢﹖答案是肯定的﹐而且是常見之寫法。如果名稱相同但是引數不一致(像引數個數不同或引數型態不同),就是父子類別之間的程式多重定義(Procedure Overloading)了,必須寫上Overloads字眼。例如﹕上述程式相當於──

'ex04.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'------------------------------------------------------------------------------------------
Class Person
  Private name As String
  Private age As Integer
  Public Sub New()
  End Sub
  Public Sub SetValue(ByVal na As String, ByVal a As Integer)
  name = na
  age = a
  End Sub
  Public Function birthDay() As Integer
  birthDay = 2001 - age
  End Function
  Public Sub Display()
  Messagebox.Show("Name: " + name + "  Age: " + str(age))
  End Sub
End Class

Class Teacher
  Inherits Person
 
  Private salary As Decimal
  Public Overloads Sub SetValue( ByVal na As String, ByVal a As Integer, ByVal
  sa As Decimal)
  SetValue(na, a)
  salary = sa
  End Sub
  Public Sub pr()
  MyBase.Display()
  Messagebox.Show("Salary: " + str(salary))
  End Sub
End Class
'------------------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Windows Form Designer generated code "
  ........
#End Region
  Protected Sub Form1_Click( ByVal sender As Object, ByVal
  e As System.EventArgs)
  Dim steven As Teacher
  steven = New Teacher()
  steven.SetValue("Steven", 35, 35000)
  steven.pr()
  End Sub
End Class

此程式輸出如下﹕
  NAME: Steven
  AGE : 35
  Salary: 35000

此種情況﹐Teacher 類別擁有兩個 SetValue()程式﹐一個由Person繼承而來﹐一個是自己定義的。同時﹐也擁有兩個Display()程式。此時﹐計算機如何分辨它們呢﹖計算機依據程式的引數來決定呼叫那一個程式,當您寫成 steven.SetValue("Steven", 35, 35000)時,此SetValue()是子類別自己的SetValue()。而寫成SetValue(na,a)時,則是由Person類別繼承而來之SetValue()程式。此VB程式已定義如下之類別關係﹕

 
接下來﹐再為Person定義一個子類別── Student。程式如下﹕

'ex05.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'------------------------------------------------------------------------------------------
Public Class Person
  Private name As String
  Private age As Integer
  Public Sub New()
  End Sub
  Public Sub SetValue(ByVal na As String, ByVal a As Integer)
  name = na
  age = a
  End Sub
  Public Function birthDay() As Integer
  birthDay = 2001 - age
  End Function
  Public Sub Display()
  Messagebox.Show("Name: " + name + "  Age: " + str(age))
  End Sub
End Class

Public Class Teacher
  Inherits Person
 
  Private salary As Decimal
  Public Overloads Sub SetValue( ByVal na As String, ByVal a As Integer, ByVal
  sa As Decimal)
  SetValue(na, a)
  salary = sa
  End Sub
  Public Sub pr()
  MyBase.Display()
  Messagebox.Show("Salary: " + str(salary))
  End Sub
End Class

Public Class Student
  Inherits Person
 
  Private student_number As Integer
  Public Overloads Sub SetValue( ByVal na As String, ByVal a As Integer, ByVal
  no As Integer)
  SetValue(na, a)
  student_number = no
  End Sub
  Public Sub pr()
  MyBase.Display()
  Messagebox.Show("StudNo: " + str(student_number))
  End Sub
End Class
'-----------------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Windows Form Designer generated code "
  ........
#End Region
  Protected Sub Form1_Click( ByVal sender As Object, ByVal
  e As System.EventArgs)
  Dim x As New Person()
  x.SetValue("Alvin", 32)
  Dim y As New Student()
  y.SetValue("Tom", 36, 11138)
  x.Display()
  y.pr()
  End Sub
End Class

此程式輸出﹕
  Name: Alvin  Age: 32
  Name: Tom  Age: 36
  StudNo: 11138

  此時﹐Student 類別含有name、age 及student_number三個資料成員。而且擁有 SetValue()、Person.SetValue() 、Display()、pr() 及birthYear()五個程式成員。於是建立了如下之繼承關係﹕
 
 
  x 物件含name及age 兩項資料﹐指令──x.SetValue ("Alvin", 32)﹐將資料存入x 物件中。因Student繼承Person﹐所以y 物件內含name、age 及student_number三項資料﹐指令──y.SetValue("Tom", 36, 11138) 將資料存入y 物件中。上述 SetValue()程式之功能是﹕設定物件之初值。可由建構者(Constructor) 代替之。所以此Student之定義相當於──

'ex06.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms

'----------------------------------------------------
Public Class Person
  Private name As String
  Private age As Integer
  Public Sub New()
  End Sub
  Public Sub SetValue(ByVal na As String, ByVal a As Integer)
  name = na
  age = a
  End Sub
  Public Function birthDay() As Integer
  birthDay = 2001 - age
  End Function
  Public Sub Display()
  Messagebox.Show("Name: " + name + "  Age: " + str(age))
  End Sub
End Class

Public Class Teacher
  Inherits Person
 
  Private salary As Decimal
  Public Overloads Sub SetValue(ByVal na As String, ByVal a As Integer, ByVal sa As Decimal)
  SetValue(na, a)
  salary = sa
  End Sub
  Public Sub pr()
  MyBase.Display()
  Messagebox.Show("Salary: " + str(salary))
  End Sub
End Class

Public Class Student
  Inherits Person
 
  Private student_number As Integer
  Public Sub New(ByVal na As String, ByVal a As Integer, ByVal no As Integer)
  SetValue(na, a)
  student_number = no
  End Sub
  Public Sub pr()
  MyBase.Display()
  Messagebox.Show("StudNo: " + str(student_number))
  End Sub
End Class
'------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
 
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Windows Form Designer generated code "
  ........
#End Region
  Protected Sub Form1_Click( ByVal sender As Object, ByVal
  e As System.EventArgs)
  Dim x As New Person()
  x.SetValue("Alvin", 32)
  Dim y As New Student("Tom", 36, 11138)
  x.Display()
  y.pr()
  End Sub
End Class

此程式輸出﹕
  Name: Alvin  Age: 32
  Name: Tom  Age: 36
  StudNo: 11138

子類別之建構者呼叫父類別之SetValue()來設定物件初值。請仔細看y 物件之誕生過程﹕y 誕生時﹐建構者──

  Public Sub New(ByVal na As String, ByVal a As Integer, ByVal no As Integer)
  SetValue(na, a)
  student_number = no
  End Sub

它先呼叫父類別的自然建構者Person.New()一起誕生y 物件。此時﹐Person.New()誕生如下﹕
 
繼承部分是Person.New()誕生的。Person.New()任務完成了﹐輪到Student的建構者本身誕生(擴充)如下﹕

 

  誕生完畢﹐開始Student建構者內之指令以設定y 之初值。首先呼叫父類別的SetValue() ﹐於是SetValue()將值存入y 如下﹕

 
 
最後﹐執行指令── student_number = no﹐設定student_number資料之初值﹕
 
 

於是﹐Student的建構者誕生y 物件﹐也設定初值﹐功成圓滿。
  上述的Student建構者呼叫父類別之自然建構者(因為Person類別未定義建構者﹐計算機自動產生自然建構者)來協助誕生物件。如果Person類別定義了建構者﹐Student建構者便能直接呼叫Person建構者了。例如﹕

'ex07.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'-----------------------------------------------------------------------------------------
Public Class Person
  Private name As String
  Private age As Integer
  Public Sub New(ByVal na As String, ByVal a As Integer)
  name = na
  age = a
  End Sub
  Public Function birthDay() As Integer
  birthDay = 2001 - age
  End Function
  Public Sub Display()
  Messagebox.Show("Name: " + name + "  Age: " + str(age))
  End Sub
End Class

Public Class Teacher
  Inherits Person
 
  Private salary As Decimal
  Public Sub New(ByVal na As String, ByVal a As Integer, ByVal sa As Decimal)
  MyBase.New(na, a)
  salary = sa
  End Sub
  Public Sub pr()
  MyBase.Display()
  Messagebox.Show("Salary: " + str(salary))
  End Sub
End Class

Public Class Student
  Inherits Person
 
  Private student_number As Integer
  Public Sub New(ByVal na As String, ByVal a As Integer, ByVal no As Integer)
  MyBase.New(na, a)
  student_number = no
  End Sub
  Public Sub pr()
  MyBase.Display()
  Messagebox.Show("StudNo: " + str(student_number))
  End Sub
End Class
'-----------------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
 
#Region " Windows Form Designer generated code "
  ........
#End Region
  Protected Sub Form1_Click( ByVal sender As Object, ByVal 
  e As System.EventArgs)
  Dim x As New Person("Alvin", 32)
  Dim y As New Student("Tom", 36, 11138)
  x.Display()
  y.pr()
  End Sub
End Class

此程式輸出﹕
  Name: Alvin  Age: 32
  Name: Tom  Age: 36
  StudNo: 11138

子類別之建構者──

  Public Sub New(ByVal na As String, ByVal a As Integer, ByVal sa As Decimal)
  ......
  End Sub

先呼叫父類別之建構者──

 Public Sub New(ByVal na As String, ByVal a As Integer)
  ......
 End Sub

協助誕生物件如下﹕
 
 接著﹐執行父類別Person的建構者內之指令﹐設定初值如下﹕
 
Person建構者工作完成了﹐輪到Student建構者的工作﹐擴充物件如下﹕

 

誕生完畢﹐執行Student建構者內之指令﹐設定初值﹕

 
於是﹐y 物件誕生完畢了。
  子類別建構者呼叫父類別建構者之﹕

 
 
例如﹐Student建構者內的MyBase.New(na, a)指令將na及a值傳遞給Person建構者﹐於是Person建構者設定name及age之初值。除了呼叫Person建構者之外﹐還執行自己的指令──student_number = no ﹐設定student_number之初值。Student類別之物件含有三個資料成員﹐其中name及 age是由Person類別繼承而來﹐就藉Person建構者設定其初值。至於Student類別自己定義之資料成員student_number﹐就由自己的指令──student_number = no設定其初值。
3. 藉「繼承」擴充程式

  程式之發展是漸進的﹐軟體內之類別需隨企業之成長而不斷擴充。類別擴充常源於﹕
(1) 企業成長了﹐產生了新類別。
  例如﹕某計算機公司﹐過去製造大型及迷你計算機﹐現在新推出個人計算機。就必須建立新子類別如下﹕

 
  圖3、  程式擴充方法──衍生子類別

  再如﹐某銀行過去提供支票帳戶(Checking Account)及儲蓄帳戶(Saving Account)給客戶﹐現在擬增加定期帳戶(CD Account)。就得新增子類別如下﹕

 

  這新類別CD_Account繼承父類別Saving_Account及Account 的資料及程式。例如﹐Account 之定義如下﹕

'ex08.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'-----------------------------------------------------------------------------------
Class Account
  Private Shared next_number As Integer
  Protected acc_no As Integer
  Protected name As String
  Protected balance As Decimal
 
  Shared Sub New()
  next_number = 1000
  End Sub
  Public Sub New(ByVal na As String)
  name = na
  balance = 0
  acc_no = next_number
  next_number = next_number + 1
  End Sub
  Public Sub deposit(ByVal money As Decimal)
  balance = balance + money
  End Sub
  Public Sub withdraw(ByVal money As Decimal)
  balance = balance - money
  End Sub
  Public Sub close()
  acc_no = -1
  End Sub
End Class

Class Saving_Account
  Inherits Account
 
  Private interest_rate As Double
  Public Sub New(ByVal na As String, ByVal rate As Double)
  MyBase.New(na)
  Me.interest_rate = rate
  End Sub
  Public Function comp_interest() As Double
  comp_interest = balance * interest_rate
  End Function
  Public Sub display()
  Messagebox.Show("ACC_NO: " + str(MyBase.acc_no))
  Messagebox.Show("餘額: " + str(Me.balance) + "  利息: "
  + str(comp_interest()))
  End Sub
End Class
'-----------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Windows Form Designer generated code "
  .......
#End Region
  Protected Sub Form1_Click( ByVal sender As Object, ByVal
  e As System.EventArgs)
  Dim saving_acc As New Saving_Account("Tom Bush", 0.085)
  Dim account As Saving_Account
  account = New Saving_Account("Linda Lin", 0.008)
  account.deposit(5000)
  account.withdraw(2500)
  account.display()
  account.close()
  End Sub
End Class

此程式輸出﹕
  ACC_NO: 1001
  餘額: 2500
  利息: 20
  因Saving_Account繼承Account ﹐所以Saving_Account類別亦擁有deposit() 、withdraw()及close() 三個程式。請換個角度﹐從Saving_Account類別之設計者來看﹐他透過繼承關係來「借用」父類別之程式。「借用」又稱為「再使用」(Resue) ﹐能使得子類別簡單但卻強而有力。就如Saving_Account類別顯得比Account 類別簡單﹐但它總共卻含有deposit() 、withdraw()等6 個程式﹐功能比Account 類別強大許多。對於指令──account.deposit(5000) 而言﹐其有兩種意義﹕
  I. Saving_Account繼承Account ﹐所以Saving_Account具有deposit() 程式﹐可將5000存入account 物件。
  II. Saving_Account為Account 之子類別﹐它能借用(再使用)父類別之deposit() 程式﹐來將5000存入account 物件。

  這兩者是一體的兩面﹐繼承功能讓軟體師能不斷新增子類別﹐不斷再使用現有類別之程式﹐來簡化子類別之複雜度。繼承使得子類別擁有祖父類別之各種功能﹐且再增加新功能﹔再使用使得子類別儘量委託祖父類別來擔任工作﹐自己以逸待勞。因而﹐善用繼承功能﹐時時心存再使用觀念﹐便能設計簡單卻功能強大的子類別了。而程式設計師的提升了﹐軟體之成本下降了﹐此乃 的理想目標之一。茲再擴充一個子類別CD_Account如下﹕

'ex09.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'--------------------------------------------------------------------------------
Class Account
  Private Shared next_number As Integer
 
  Protected acc_no As Integer
  Protected name As String
  Protected balance As Decimal
 
  Shared Sub New()
  next_number = 1000
  End Sub
  Public Sub New(ByVal na As String)
  name = na
  balance = 0
  acc_no = next_number
  next_number = next_number + 1
  End Sub
  Public Sub deposit(ByVal money As Decimal)
  balance = balance + money
  End Sub
  Public Sub withdraw(ByVal money As Decimal)
  balance = balance - money
  End Sub
  Public Sub close()
  acc_no = -1
  End Sub
End Class

Class Saving_Account
  Inherits Account
 
  Private interest_rate As Double
  Public Sub New(ByVal na As String, ByVal rate As Double)
  MyBase.New(na)
  Me.interest_rate = rate
  End Sub
  Public Function comp_interest() As Double
  comp_interest = balance * interest_rate
  End Function
  Public Sub display()
  Messagebox.Show("ACC_NO: " + str(MyBase.acc_no))
  Messagebox.Show("餘額: " + str(Me.balance) + "  利息: "
  + str(comp_interest()))
  End Sub
End Class

Class CD_Account
  Inherits Saving_Account

  Public Sub New(ByVal na As String, ByVal rate As Double, ByRef b As Decimal)
  MyBase.New( na, rate + 0.003 )
  MyBase.deposit(b)
  End Sub
End Class
'----------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Windows Form Designer generated code "
  .......
#End Region
  Protected Sub Form1_Click( ByVal sender As Object, ByVal
  e As System.EventArgs)
  Dim a As CD_Account
  a = New CD_Account("Linda Lin", 0.008, 2500)
  a.display()
  a.close()
  End Sub
End Class

CD_Account除了在定義自己的New()之外,皆繼承Saving_Account的成員。請您仔細閱讀下述程式,看看跟上一個程式有何微妙差異?

'ex10.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'--------------------------------------------------------------------------------
Class Account
  Private Shared next_number As Integer
 
  Protected acc_no As Integer
  Protected name As String
  Protected balance As Decimal
 
  Shared Sub New()
  next_number = 1000
  End Sub
  Public Sub New(ByVal na As String)
  name = na
  balance = 0
  acc_no = next_number
  next_number = next_number + 1
  End Sub
  Public Sub deposit(ByVal money As Decimal)
  balance = balance + money
  End Sub
  Public Sub withdraw(ByVal money As Decimal)
  balance = balance - money
  End Sub
  Public Sub close()
  acc_no = -1
  End Sub
End Class

Class Saving_Account
  Inherits Account
 
  Private interest_rate As Double
  Public Sub New(ByVal na As String, ByVal rate As Double)
  MyBase.New(na)
  Me.interest_rate = rate
  End Sub
  Public Function comp_interest() As Double
  comp_interest = balance * interest_rate
  End Function
  Public Sub display()
  Messagebox.Show("ACC_NO: " + str(MyBase.acc_no))
  Messagebox.Show("餘額: " + str(Me.balance) + "  利息: "
  + str(comp_interest()))
  End Sub
End Class

Class CD_Account
  Private acc As Saving_Account
  Public Sub New(ByVal na As String, ByVal rate As Double, ByRef b As Decimal)
  acc = New Saving_Account(na, rate + 0.003)
  acc.deposit(b)
  End Sub
  Public Function comp_interest() As Double
  comp_interest = acc.comp_interest()
  End Function
  Public Sub display()
  acc.display()
  End Sub
  Public Sub Close()
  acc.close()
  End Sub
End Class
'----------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Windows Form Designer generated code "
  .......
#End Region
  Protected Sub Form1_Click( ByVal sender As Object, ByVal
  e As System.EventArgs)
  Dim a As CD_Account
  a = New CD_Account("Linda Lin", 0.008, 2500)
  'a.deposit(5000)  'Error here!!
  a.display()
  a.close()
  End Sub
End Class

(2) 環境改變了﹐必須修正舊類別。
  例如﹕軟體內含Sales 類別如下──

'ex11.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'----------------------------------------------------------------------------------
Class Sales
  Protected sum As Double
  Public Sub New()
  sum = 0
  End Sub
  Public Overridable Sub input(ByVal amount As Double)
  sum = sum + amount
  End Sub
  Public Sub display()
  Messagebox.Show("The Sum Is: " + str(sum))
  End Sub
End Class
'-----------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Windows Form Designer generated code "
  ........
#End Region
  Protected Sub Form1_Click( ByVal sender As Object, ByVal
  e As System.EventArgs)
  Dim x As New Sales()
  x.input(3000.5)
  x.input(7999.5)
  x.input(15000)
  x.display()
  End Sub
End Class

此程式輸出如下﹕The Sum Is: 26000

input() 輸入銷售金額﹐且將金額加總起來﹐存於 sum變數中。display() 顯示出總金額。隨著企業之成長﹐往往對軟體之功能有新的需求。例如﹕希望程式輸出平均銷售額。此時﹐必須原來的軟體﹐其方法有二﹕

(I) 改寫 Sales類別之定義。
  此為傳統軟體之維護方法﹐就像一座房屋﹐已不敷使用﹐於是用推土機推掉﹐重建之。通常這種方法並不佳﹐原因是﹕舊的軟體有些功能仍然可用﹐廢棄重建實在可惜。若不想重建﹐只想去修改它﹐但是軟體若很龐大﹐得浪費人力去了解舊軟體的結構﹐弄通了之後﹐才能加以修正﹐顯然不經濟。進一步想﹐於修正之過程中﹐不經意而更動舊軟體內仍可用之部分﹐則原來正確之功能﹐反而有遭破壞之虞﹗
(II) 藉繼承關係修正 Sales類別。
  亦即定義 Sales之子類別﹐來修正及擴充 Sales之功能。此時﹐並未更動Sales 類別之定義﹐所以不會破壞 Sales之功能。既然儲存原有的良好功能﹐又能增加新的功能﹐豈非兩全其美呢﹖此「舊幹發新枝」之景象即是千年神木得以茁壯且綠意盎然之道理﹐也正是 OOP魅力的源頭。現在﹐就為 Sales定義個子類別叫 Sales_new如下﹕

'ex12.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'------------------------------------------------------------------------------------
Class Sales
  Protected sum As Double
  Public Sub New()
  sum = 0
  End Sub
  Public Overridable Sub input(ByVal amount As Double)
  sum = sum + amount
  End Sub
  Public Sub display()
  Messagebox.Show("The Sum Is: " + str(sum))
  End Sub
End Class

Class Sales_new
  Inherits Sales
 
  Protected number As Integer
  Public Sub New()
  number = 0
  End Sub
  Public Overrides Sub input(ByVal amount As Double)
  MyBase.input(amount)
  number = number + 1
  End Sub
  Public Sub display_average()
  Dim avg As Double
  If number > 0 Then
  avg = sum / number
  MessageBox.Show("The Average Is : " + str(avg))
  End If
  End Sub
End Class
'------------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Windows Form Designer generated code "
  .......
#End Region
  Protected Sub Form1_Click( ByVal sender As Object, ByVal
  e As System.EventArgs)
  Dim x As New Sales_new()
  x.input(3005.5)
  x.input(5994.5)
  x.input(15012.6)
  x.display()
  x.display_average()
  End Sub
End Class


此程式輸出﹕
  The Sum Is: 24012.6
  The Average Is: 8004.2

  子類別增加了新資料項number﹐重新定義了input()﹐使新input()儲存父類別內之input()功能﹐並加上number = number +1之運算。保留了父類別之display()﹐但增加了display_average()程式。依此方法﹐軟體自然日益茁壯﹐且歷久彌新﹗藉繼承關係不斷擴充乃為OOP之重要技術﹐盼您善用之。n

 


 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-988982/,如需轉載,請註明出處,否則將追究法律責任。

相關文章