跳转到内容

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

为以下类绘制继承图

摩托车、自行车、车辆、脚踏车、三轮车。

答案


为以下类绘制继承图

怪物、角色、龙、英雄、兽人

答案


华夏公益教科书