VB.Net中文教程(1) 类别与封装性
2024-07-10 13:01:18
供稿:网友
1. 类别的「程序成员」(procedure member)
类别 (class)之任务是把资料(data)和程序(procedure)组织并封装起来。类别告诉计算机﹕「其对象应含有那些资料、应含有那些程序裨处理外界传来之讯息」。类别须详细说明它的资料及程序﹐我们称此资料是类别之「资料成员」(data member) ﹔而称此程序是类别之「程序成员」(procedure member)。有关类别内容之叙述﹐就是所谓的类别定义(class definition)。类别定义之格式为──
类别之用途为﹕宣告对象。例如﹕
'ex01.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'----------------------------------------------------
class tree
public varity as string
public age as integer
public height as single
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 new tree()
msgbox("object a is created.")
end sub
end class
此程序定义了类别tree﹐它只含资料而无程序﹐为一「阳春型」之类别。当计算机执行到form1_click()程序内之宣告指令──
dim a as new tree()
就分配足够存放这 3项资料的内存空间给予对象 a。然而﹐此tree类别只有资料而无程序。所以﹐对象 a无法接受外来之讯息。此时﹐可加入程序成员﹐使tree类别含有程序、具有动力﹐对象就有能力来处理讯息了。例如﹕
'ex02.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'------------------------------------------------------------
class tree
public varity as string
public age as integer
public height as single
public sub input(byval hei as single)
height = hei
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 new tree()
a.input(2.1)
messagebox.show("set a.height to 2.1", "hello!")
end sub
end class
此程序输出:set a.height to 2.1
现在﹐tree类别已拥有程序成员 input()。程序成员的写法与一般vb程序相同﹐只是它应宣告于类别内﹐成为类别之专属程序。此刻﹐对象 a含有 3项资料及 1个程序﹕
计算机执行到指令──
a.input(2.1)
就将讯息──input(2.1)传给对象 a。此时计算机呼叫并执行对象 a内之input() 程序。对象 a内之 input()就是定义于tree类别内之input() ﹔于是form1_click()就把自变量──2.1 传给 input()内之 hei变量。
接下来﹐叙述──
height = hei
把 hei变量值存入对象 a之资料成员──height中。
此刻﹐对象 a对讯息之处理完成了﹐其内部资料改变了﹐亦即对象 a之内部状态(internal state)改变了﹔这是对象的行为之一。上述您已经会加入一个程序了﹐依同样方法﹐继续加入其它程序﹐让对象的兴为更多采多姿。例如﹕
'ex03.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'-----------------------------------------------------------------------
class tree
public varity as string
public age as integer
public height as single
public sub input(byval hei as single)
height = hei
end sub
public function inquireheight() as single
inquireheight = height
end function
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 tree = new tree()
dim h as single
a.input(2.1)
h = a.inquireheight()
messagebox.show("height = " + str(h) + "公尺", "hi!")
end sub
end class
此程序输出如下﹕height = 2.1公尺
tree类别有2个程序成员──input() 和inquireheight()。类别之程序成员必须与其对象配合使用。格式为﹕
亦即﹐必须以讯息之形式出现。例如﹕
如果程序成员不与对象相配合时﹐计算机会如何处理呢﹖例如﹕
'ex04.bas
'some error here !
imports system.componentmodel
imports system.drawing
imports system.winforms
'--------------------------------------------------------------
class tree
public varity as string
public age as integer
public height as single
public sub input(byval hei as single)
height = hei
end sub
public function inquireheight() as single
inquireheight = height
end function
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 tree = new tree()
dim h as single
a.input(2.1)
h = inquireheight()
messagebox.show("height = " + str(h) + "公尺", "hi!")
end sub
end class
当计算机看到form1_click()内之指令──
h = inquireheight( )
它视inquireheight()为一独立之程序﹐与tree类别内之inquireheight()无关﹔于是计算机去找此inquireheight()之定义﹐但找不着﹔所以程序错了。因之﹐您要掌握个原则── 程序成员之唯一任务是支持对象之行为﹐必须与对象配合使用。
2. 「封装性」概念
对象把资料及程序组织并「封装」(encapsulate) 起来﹐只透过特定的方式才能使用类别之资料成员和程序成员。对象如同手提袋﹐只从固定的开口才能存取东西﹐否则您一定不敢把钱放在手提袋中。对象像一座「防火墙」保护类别中的资料﹐使其不受外界之影响。想一想我国的万里长城可保护关内的人民﹐避免受胡人侵犯﹐但长城并非完全封闭﹐而有山海关、玉门关等出入口。对象和万里长城之功能是一致的﹐它保护其资料成员﹐但也有正常的资料存取管道﹕以程序成员来存取资料成员。请看个程序﹕
'ex05.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'-------------------------------------------------------
class tree
public varity as string
public age as integer
public height as single
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 new tree()
a.height = 2.1
messagebox.show("height = " + str(a.height) + "公尺")
end sub
end class
此程序输出如下﹕height = 2.1公尺
此程序中﹐tree类别含有 3个资料成员﹐即对象内含有3个资料值,此类别之程序成员能直接存取之。同时,也允许其它程序来存取资料成员之值﹐其存取格式为﹕
例如﹕
a.height = 2.1
此指令把 2.1存入对象 a之height变量中。于是对象 a之内容为﹕
请看个常见错误如下﹕
'ex06.bas
'some error here!
imports system.componentmodel
imports system.drawing
imports system.winforms
'-------------------- ------------------------------------
class tree
public varity as string
public age as integer
public height as single
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 new tree()
height = 2.1
messagebox.show("height = " + str(a.height) + "公尺")
end sub
end class
form1_click()程序内之指令── height = 2.1,此height变量并未与对象配合使用﹐计算机不认为它是tree类别之height变量。计算机视其为form1_click()之自动变量(automatic variable)﹐但却未见到它的宣告﹐因之程序错了﹗这是对象对其资料成员保护最松的情形﹐因为对象所属类别(即tree)之外的程序(如form1_click()程序)尚能存取资料成员的内容。就像一颗炸弹﹐除了引信管外﹐尚有许多管道可使炸弹内之化学药品爆炸﹔您将不敢把炸弹摆在飞机上﹐因何时会爆炸将无法控制。同理﹐tree类别之资料──height变量﹐连外部的form1_click()皆可随意改变它﹔那么有一天height之内容出问题了﹐将难以追查出错之缘故﹐这种程序将让您大伤脑筋﹐因为您已无法掌握状况了。
现在的vb程序中﹐能采取较严密之保护措施﹐使您较能控制类别内资料的变化状况。例如﹐
'ex07.bas
'some error here!
imports system.componentmodel
imports system.drawing
imports system.winforms
'-----------------------------------------
class tree
private varity as string
private age as integer
private height as single
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
public sub form1_click( byval sender as object, byval
e as system.eventargs)
dim a as new tree()
a.height = 2.1
messagebox.show("height = " + str(a.height))
end sub
end class
此程序将原来的public专用字改为private﹐对tree类别之资料成员采取严格之保护措施。public 与private之区别为──
public 表示此类别外之程序可来存取资料成员。
private 表示此类别外之程序绝无法直接存取资料成员﹐只有程序成员才能存取资料成员。
所以﹐计算机看到指令── a.height = 2.1,因tree类别采取严格保护措施(private)﹐则form1_click()程序不能使用height变量名称。所以指令── a.height = 2.1错了。也许您问道﹕这样岂不是无法存取类别内之资料成员吗﹖答案是﹕「类别内之程序成员(member function) 可存取资料成员﹐而类别外之程序能藉程序成员代之存取资料成员。」
图1、类别之沟通管道──程序成员
这如同﹐引信管才能引起炸弹内之化学药品爆炸﹐人们只能经由引信管引爆之﹐让人们觉得使用炸弹既安全又简单。同样地﹐对象经由程序成员和外界沟通﹐可减少外界无意中破坏对象内之资料(无意中引爆炸弹)。例如﹕
'ex08.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'--------------------------------------------------
class tree
private varity as string
private age as integer
private height as single
public sub input(byval hei as single)
height = hei
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 new tree()
a.input(2.1)
messagebox.show("ok")
end sub
end class
将input()摆在tree类别中﹐为tree之程序成员﹐它能存取资料成员height之值。把input()程序宣告为public表示类别外之程序可藉来呼叫它﹐其呼叫格式为──
简单规则是﹕
public 表示授权给外界之程序藉由此格式呼叫程序成员。
如果此程序改写为﹕
'ex09.bas
'some error here!
imports system.componentmodel
imports system.drawing
imports system.winforms
'----------------------------------------------
class tree
private varity as string
private age as integer
private height as single
private sub input(byval hei as single)
height = hei
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 new tree()
a.input(2.1)
messagebox("ok")
end sub
end class
这程序有问题﹐因为 input()是tree类别之private程序成员而非public程序成员﹐所以不能使用如下格式──
所以此程序错了。 请再看个例子吧﹗
'ex10.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'-------------------------------------------
class tree
private varity as string
private height as single
public age as integer
public sub showage()
messagebox.show("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 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 new tree()
a.age = 8
a.age = a.age + 2
a.showage()
end sub
end class
tree类别包含 2个private成员── variety及height﹐且有 2个public成员── age及 showage()。由于age是public资料成员﹐所以fom1_click()可使用格式──
来存取tree内之age变量。指令── a.age = 8把8存入对象 a内之age 变量。指令──a.age = a.age + 2使对象a之age变量值加上2﹐成为10。由于showage()程序是public程序成员﹐也可使用格式──
来呼叫 showage()程序。
由于类别(即对象)之目的是保护资料﹐并且提供程序成员来与外界沟通(接受、处理、并反应讯息)。通常﹐资料成员皆宣告为private﹐而程序成员皆宣告为public。亦即尽量少用格式──
而尽量多用格式──
例如﹕
'ex11.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'--------------------------------------------------------------------
class tree
private varity as string
private age as integer
private height as single
public sub input(byval v as string, byval a as integer, byval hei as single)
varity = v
age = a
height = hei
end sub
public sub show()
messagebox.show(varity + ", " + str(age) + ", " + str(height))
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, b as new tree()
a.input("peach", 8, 2.1)
b.input("pinapple", 2, 0.5)
a.show()
b.show()
end sub
end class
这个vb程序﹐tree内之资料成员──variety, age及height皆为private成员,而input()及show()程序是public成员。form1_click()程序中﹐首先诞生对象── a及 b。接下来﹐指令──
把 3项资料分别存入对象 a之资料成员中﹐a 之内容为﹕
同样地﹐指令──
b.input( "pineapple", 2, 0.5 )
也把 3项资料存入对象 b之中﹐则 b之内容为﹕
最后﹐呼叫show()程序把对象 a和对象 b之内容显示出来﹕
peach, 8, 2.1
pineapple, 2, .5
n