跳轉到內容

A-level 計算機科學/AQA/試卷 1/程式設計基礎/OOP 技術

來自華夏公益教科書,開放的書籍,開放的世界

OOP 技術

[編輯 | 編輯原始碼]

技術

  • 封裝
  • 聚合
* association aggregation
* composition aggregation
  • 重寫

OOP 中的最佳實踐

[編輯 | 編輯原始碼]

OOP 可能是當今使用最廣泛的程式設計正規化。因此,它有許多不同的使用方式,以及關於 OOP 語言中良好和不良程式設計風格的許多想法。但是,有三個核心理念,它們普遍被認為在大多數或所有 OOP 情況下都是有價值的

  • 封裝您的資料,僅在需要知道的情況下才允許訪問
  • 在您有選擇的情況下:選擇組合而不是繼承
  • 在將不同的程式碼片段連線在一起時,使用介面,而不是直接引用它們

這三個理念通常縮寫為

  • "封裝變化"
  • "優先組合而不是繼承"
  • "面向介面程式設計,而不是實現"

原始 OOP 文章如下,僅進行了一些細微更改,例如拼寫更正


OO - PIIE

[編輯 | 編輯原始碼]

在談論 OOP 時,您必須記住以下內容

00 - PIIE!

其中

  • 00 = 面向物件 以及
  • PIIE = 多型 / 繼承 / 例項化 / 封裝
您只能透過介面(公共方法)訪問私有屬性和方法

您會注意到我們不必對屬性使用 dim 語句,而是使用了 private 一詞。這意味著一旦您例項化了該類,這些屬性就無法直接訪問。讓我們以 polo 類為例

polo.fuel = 100 'this would be acceptable (but not in the exam!)

在示例中,我們訪問了 polo 類的 fuel 屬性,併為汽車提供了 100 個單位的燃料,因為 fuel 被宣告為 public,在訪問它時沒有任何限制。但是,當我們嘗試以下操作時,我們會遇到麻煩

polo.maxSpeed = 100 'this would be unacceptable

這不起作用的原因是,我們已經將 maxSpeed 屬性宣告為 private。如果某些內容被宣告為 private,則無法從外部訪問它,但是您如何訪問它呢?訪問私有方法或屬性的唯一方法是使用介面或公共方法。在汽車程式碼示例中,我們有

public sub setSpeed(byVal s as integer) 'declaring an interface
   maxSpeed = s
end sub

由於此方法是公共的,因此我們可以透過以下方式呼叫它:polo.setSpeed(100)。由於 setSpeed 在汽車物件內部宣告,因此它可以訪問所有私有屬性和方法。

我們還需要找出汽車的速度以顯示給使用者,我們可以透過建立 get 例程來做到這一點

public function getSpeed() 'declaring an interface (a function as we are returning a value)
   return maxSpeed
end function

由於此方法是公共的,因此我們可以透過以下方式呼叫它:polo.getSpeed()。由於 getSpeed 在汽車物件內部宣告,因此它可以訪問所有私有屬性和方法。

一般來說,屬性應該始終宣告為私有,並且只能透過介面訪問,使用 setX 命令為私有變數 X 提供一個新值,並使用 getX 命令返回 X 的值。您永遠不應該直接訪問 X!

練習:封裝

為汽車宣告一個顏色屬性,該屬性只能透過介面訪問

答案

private colour as string 'this must be private!
編寫一個介面來設定顏色

答案

public sub setColour(byVal c as string) 'declaring an interface, make sure it's public!
   colour = c
end sub
編寫一個介面來返回顏色

答案

public function getColour() 'it must be a function to return a value
   return colour
end function

建立一個演員類,具有以下內容

  • 屬性:健康值、敏捷度、x、y、力量
  • 方法:walkforward()、eat()、gethit()、displaystats()、setHealth(p)、setLocation(px,py)

答案

Class actor
 Private health As Integer
 Private name As String
 Private x As Integer
 Private y As Integer

 Public Sub setName(ByVal p)
  name = p
 End Sub

 Public Sub walkforward()
  x = x + 1
 End Sub

 Public Sub eat()
  health = health + 10
  Console.WriteLine("Nom Nom Nom")
 End Sub

 Public Sub gethit()
  health = health - 10
  Console.WriteLine("Argh!")
 End Sub

 Public Sub displaystats()
  Console.WriteLine("Character :" & name)
  Console.WriteLine("Health :" & health)
  Console.WriteLine("Location :" & x & ", " & y)
 End Sub

 Public Sub setHealth(ByVal p)
  health = p
 End Sub

 Public Sub setLocation(ByVal px, ByVal py)
  x = px
  y = py
 End Sub

End Class

對於上面宣告的演員類,例項化

  • 名為 Barry 的巫師,健康值為 100,起始位置為 4,5
  • 名為 Herbert 的獸人,健康值為 35,起始位置為 20,2,然後報告他的狀態

答案

dim wizard as new actor  'it doesn't have to be named wizard, it could have another name
dim orc as new actor     'it doesn't have to be named orc, it could have another name

wizard.setName("Barry") 'remember to use your get and set routines!
wizard.setHealth(100)
wizard.setLocation(4,5)

orc.setName("Herbert")
orc.setHealth(35)
orc.setLocation(20,2)
orc.displaystats()
程式設計 Get 和 Set 例程

封裝是一件非常普遍的事情,以至於一些語言為建立 get 和 set 例程提供了捷徑。在 VB.NET 中,這涉及使用 property

Private _fuel As Integer

Public Property Fuel() As Integer
    Get
        Return _fuel
    End Get
    Private Set(ByVal value As Integer)
        _fuel = value
    End Set
End Property

由於我們永遠不會直接呼叫 _fuel,因此它在開頭有一個下劃線並不重要。使用此程式碼,我們可以執行以下方法,而無需將 fuel 屬性設定為 public

lada.fuel = 23
Console.Writeline(lada.fuel)

繼承圖

[編輯 | 編輯原始碼]
CPT-OOP-inheritance.svg
車輛的繼承圖,所有車輛都共享來自父類“車輛”的屬性和函式。
  • 卡車繼承了車輛,並添加了自己的屬性和方法
  • 汽車繼承了車輛,並添加了自己的屬性和方法
  • 電動汽車繼承了汽車(因此也繼承了車輛),並添加了自己的屬性和方法
  • 汽油車繼承了汽車(因此也繼承了車輛),並添加了自己的屬性和方法

注意箭頭的方向,如果方向錯誤,您會被扣分。

練習:繼承圖


以上圖中汽車的父類是什麼?

答案

vehicle

為以下類繪製繼承圖

摩托車、腳踏車、車輛、腳踏車、三輪車。

答案


為以下類繪製繼承圖

怪物、角色、龍、英雄、獸人

答案


華夏公益教科書