|
|
| QUẢNG CÁO |

|
|
| THỐNG KÊ |
|
Số bài giảng: 213
Số chuyên mục: 35
Số thành viên: 660775
Lượt truy cập: 1316849
Đang online: 8226
|
|
|
|
Đang tải dữ liệu...
|
|
Đang tải dữ liệu, bạn đợi chút nha...
|
|
|
|
Trang chủ >> Lập trình phần mềm >> Visual Basic.NET
|
|
Đang tải dữ liệu, bạn đợi chút nha...
|
 |
Bài 5 - Những chức năng Đối Tượng mới của VB.NET (phần II) |
Dùng OO trong VB.NET
Tạo một Class mới
Class KeywordTrong một .vb file ta có
thể viết nhiều Classes, code của mỗi Class nằm trong một Class ...
End Class block. Thí dụ:
Public Class TheClass Public Sub Greeting() MessageBox.Show("Hello world", MsgBoxStyle.Information, "TheClass") End Sub End Class
| MessageBox.Show và
MsgBoxStyle.Information trong VB.NET thay thế MsgBox và vbInformation trong
VB6.
Classes và NamespacesNhắc lại là .NET
dùng Namespace để sắp đặt các Classes cho thứ tự theo nhóm, loại.
Namespaces được declared với một Block Structure giống như sau:
Namespace Vovisoft Public Class TheClass Public Sub Greeting() MessageBox.Show("Hello world", MsgBoxStyle.Information, "TheClass") End Sub End Class End Namespace
| Muốn nói đến bất cứ Class, Structure,
hay thứ gì được declared bên trong một Namespace...End Namespace
block ta phải dùng tên Namespace trước. Thí dụ:
Private myObject As Vovisoft.TheClass
| Một source file có thể chứa nhiều
Namespaces, và bên trong mỗi Namespace lại có thể có nhiều
Classes.
Ngoài ra, Classes thuộc về cùng một Namespace có thể nằm
trong nhiều files khác nhau trong một VB.NET project.
Thí dụ ta có
một source file với code như sau:
Namespace Vovisoft Public Class TheClass ' Code End Class End Namespace
| Và một source file khác trong cùng
project với code:
Namespace Vovisoft Public Class TheOtherClass ' Code End Class End Namespace
| Vậy thì trong Namespace
Vovisoft ta có hai Classes TheClass và
TheOtherClass.
Nhớ là, by default, Root Namespace của
một VB.NET project là tên của project ấy. Khi ta dùng Namespace block
structure là chúng ta đang thêm một tầng tên vào Root Namespace. Do đó,
trong thí dụ trên nếu tên project là MyProject thì, từ bên ngoài
project ấy, ta có thể declare một variable như sau:
Private myObject As MyProject.Vovisoft.TheClass
|
Tạo ra MethodsMethods trong
VB.NET có hai thứ: Sub và Function. Function thì phải
return một kết quả. By default, parameters của Method là ByVal
chớ không phải ByRef. Tức là nếu muốn parameter nào ByRef thì phải
nhớ khai ra rõ ràng.
Nhắc lại là khi một variable được passed vào
trong một method bằng ByVal thì system cho method đó một copy (bản
sao) của variable, do đó, trị số của variable không bị thay đổi bởi công tác
của method. Ngược lại, nếu một variable được passed vào trong một method
bằng ByRef thì method dùng chính variable đó, do đó, trị số của
variable có thể bị thay đổi bởi công tác của method.
Ta có thể giới
hạn việc sử dụng một method bằng cách áp đặt một Access Modifier (sửa
đổi quyền truy nhập) hay còn gọi là Scoping keyword (phạm vi hoạt
động):
- Private - chỉ cho phép code trong cùng Class được gọi.
- Friend - chỉ cho phép code trong cùng project/component được
gọi.
- Public - cho phép ai gọi cũng được.
- Protected - cho phép code trong subclasses (classes con, cháu)
được gọi.
- Protected Friend - cho phép code trong cùng project/component
hay code trong subclasses được gọi.
Tạo ra PropertiesTrong VB.NET ta chỉ
dùng một routine duy nhất cho mỗi Property, với hai chữ Get và
Set như sau (không còn dùng chữ Let của VB6 nữa):
Private mdescription As String Public Property Description() As String Set (ByVal Value As String) mdescription = Value End Set Get Description = mdescription End Get End Property
|
ReadOnly và WriteOnly propertyBây giờ
nếu Property là ReadOnly ta sẽ lấy phần Set ra và viết:
Public ReadOnly Property Age() As Integer Get Age = 3 End Get End Property
| hay WriteOnly ta sẽ ấy phần Get ra và
viết:
Private _data As Integer Public WriteOnly Property Data() As Integer Set (ByVal Value As Integer) _data = Value End Set End Property
|
Default PropertiesDefault
Property là property của Object mà program dùng khi ta chỉ cho tên của
Object và không nói rõ property nào. Thí dụ trong VB6 khi ta code:
TextBox1 = "The house of rising sun"
| VB6 hiểu rằng ta muốn dùng Default
Property text của Textbox1 nên code ấy tương đương với:
TextBox1.text = "The house of rising sun"
| Trong VB6 khi ta dùng keyword
Set với tên của Object, thí dụ như:
Dim myTextBox As Textbox Set myTextBox = TextBox1
| program sẽ hiểu là ta muốn nói đến
chính Object myTextBox . Nếu không thì nó biết ta muốn nói đến Object
Default Property mà làm biếng code cho rõ ra.
Trong VB.NET Default
Property phải là một Property array. Một Property array là một
property được Indexed (nói đến từng Item bằng con số Index) giống như
một array. Lý do chính của sự bắt buộc nầy là để khỏi lẫn lộn giữa hai
trường hợp ta nói đến Default property của một Object hay
chính Object ấy, vì trong VB.NET ta không còn dùng Set
keyword cho Object assignment nữa (ta chỉ còn dùng keyword Set trong
Property mà thôi).
Bây giờ hễ muốn nói đến Default Property của
Object thì phải dùng Index. Thí dụ để nói đến chính Object, ta code:
để nói đến Default Property Item 3
của Object, ta code:
Sự thay đổi từ VB6 nầy có nghĩa là
một property array procedure phải nhận một parameter. Thí dụ:
Private theData(100) As String Default Public Property Data(ByVal Index As Integer) As String Get Data = theData(Index) End Get Set(ByVal Value As String) theData(Index) = Value End Set End Property
| Từ nay ta không thể code:
TextBox1 = "Good morning!"
| như trong VB6 được nữa, mà phải
code:
TextBox1.text = "Good morning!"
| Vì Property Text không còn là Default
Property của TextBox.
Overloading methodsMột trong những chức
năng đa diện (Polymorphism) hùng mạnh nhất của VB.NET là overload
(quá tải, có rồi mà còn cho thêm) một method. Overloading có nghĩa là ta có
thể dùng cùng một tên cho nhiều methods - miễn là chúng có danh sách các
parameters khác nhau, hoặc là parameter dùng data type khác nhau (td: method
nầy dùng Integer, method kia dùng String), hoặc là số parameters khác nhau
(td: method nầy có 2 parameters, method kia có 3
parameters).
Overloading không thể được thực hiện chỉ bằng cách thay
đổi data type của Return value của Function. Phải có parameter
list khác nhau mới được.
Dưới đây là thí dụ ta dùng Overloading để
code hai Functions tìm data, một cái cho String, một cái cho
Integer:
Public Function FindData(ByVal Name As String) As ArrayList ' find data and return result End Function
Friend Function FindData(ByVal Age As Integer) As ArrayList ' find data and return result End Function
| Để ý là ta có thể cho mỗi overloading
Function một phạm vi hoạt động (Scope on implementation) khác nhau. Trong
thí dụ trên ta dùng Access Modifier Public cho Function đầu và
Friend cho Function sau.
Object LifecycleObject Lifecycle
(cuộc đời của Object) được dùng để nói đến khi nào Object bắt đầu hiện hữu
và khi nào nó không còn nữa. Sở dĩ ta cần biết rõ cuộc đời của một Object
bắt đầu và chấm dứt lúc nào là để tránh dùng nó khi nó không hiện hữu, tức
là chưa ra đời hay đã khuất bóng rồi.
New methodTrong VB6, khi một Object
thành hình thì Sub Class_Initialize được executed. Tương đương như
vậy, trong VB.NET ta có Sub New(), gọi là Constructor. VB.NET
bảo đảm Sub New() sẽ được CLR gọi khi Object được instantiated và nó chạy
trước bất cứ code nào trong Object.
Nếu Sub Class_Initialize của một
Class Object trong VB6 không nhận parameter thì Sub New() trong VB.NET chẳng
những có nhận parameters mà còn cho phép ta nhiều cách để gọi nó. Sự khác
biệt trong Constructors của VB6 và VB.NET rất quan trọng.
Tưởng tượng
ta có một Khuôn làm bánh bông lan; khuôn là Class còn những bánh làm
ra từ khuôn sẽ là các Objects bánh bông lan. Nếu ta muốn làm một cái bánh
bông lan với một lớp sô-cô-la trên mặt thì công tác sẽ gồm có hai bước:
- Dùng khuôn (Class) nướng một cái Object bánh bông lan (dùng Sub
Class_Initialize)
- Đổ lên mặt bánh một lớp sô-cô-la (dùng class Public Sub
ThoaSôcôla)
Đến đây, mọi chuyên tương đối ổn thỏa. Bây giờ,
nếu khách hàng muốn một cái bánh bông lan dùng trứng vịt thay vì trứng gà
thì ta chịu thua thôi, vì không có cách nào bảo Sub Class_Initialize dùng
trứng vịt thay vì trứng gà ngay trong lúc đang tạo dựng ra Object bánh bông
lan.
Sub New() trong VB.NET có thể nhận parameters nên nó có thể nhận
chỉ thị để dùng trứng vịt ngay trong lúc nướng cái Object bánh bông
lan.
Cái dạng đơn giản nhất của Sub New() mà ta có thể dùng là không
pass parameter nào cả (trong trường hợp nầy thì giống như Sub
Class_Initialize của VB6). Ta code Sub New() trong Class như sau:
Public Class BanhBongLan Public Sub New() ' Code to initialise object here End Sub End Class
| Ta instantiate một Object bánh bông
lan như sau:
Dim myBanhBongLan As New BanhBongLan()
| Để cho Users có sự lựa chọn khi
instantiate Object, ta có thể code thêm những Sub New khác, mỗi Sub dùng một
danh sách parameter khác nhau. Thí dụ:
Public Class BanhBongLan Public Sub New() ' Code to initialise object here End Sub Public Sub New(ByVal LoaiTrung As String) Select Case LoaiTrung Case "Vit" ' Code for TrứngVịt here Case "Ga" ' Code for TrứngGà here End Select End Sub
|
End Class
| Dùng cùng một tên method để implement
nhiều methods khác nhau được gọi là overload. Đó là một trường hợp đa
dạng (polymorphism) của OO programming. Trong thí dụ trên nếu
TrứngVịt và TrứngGà là hai loại Data Types khác nhau thì ta
cũng có thể dùng:
Sub New (ByVal TrứngVịt As TrứngVịtDataType)
| để instantiate bánh TrứngVịt và
Sub New (ByVal TrứngGà As TrứngGàDataType)
| để instantiate bánh
TrứngGà.
Như thế ta khỏi bận tâm với Select Case LoaiTrung khi
chỉ dùng một Sub New duy nhất với 1 parameter.
Trong
VisualStudio.NET, khi ta dùng tên của một overloaded method,
IntelliSense sẽ hiển thị để hướng dẫn ta đánh vào parameter list khác
nhau tùy theo method ta chọn.
TerminationTrong VB6 một Object sẽ bị
huỷ diệt khi cái reference (chỗ dùng đến Object) cuối cùng bị lấy đi. Tức là
khi không có code nào khác dùng Object nữa thì Object sẽ bị tự động huỷ
diệt. System giữ một counter để đếm số clients đang dùng Object. Cách nầy
hay ở chỗ khi counter trở thành 0 thì Object bị huỷ diệt ngay. Ta nói nó có
deterministic finalization, nghĩa là ta biết rõ ràng khi nào Object
biến mất.
Tuy nhiên, nếu ta có hai Object dùng lẫn nhau (gọi là
circular references), thì ngay cả đến lúc chúng không còn hoạt động
nữa, chúng vẫn hiện hữu mãi trong bộ nhớ vì cái Reference counter của cả hai
Objects không bao giờ trở thành 0. Nếu trường hợp nầy xảy ra thường lần lần
system không còn memory nữa, ta gọi đó là memory leak (bị rỉ bộ nhớ)
.
.NET dùng phương pháp khác để quản lý chuyện nầy. Cứ mỗi chốc, một
program sẽ chạy để kiểm xem có Object nào không còn reference nữa để huỷ
diệt. Ta gọi đó là Garbage Collection (nhặt rác). Ngay cả trường hợp
hai Objects có circular references nhưng nếu không có code nào khác
reference một trong hai Objects thì chúng cũng sẽ được huỷ diệt. Có điều,
công tác nhặt rác chạy in the background (phía sau hậu trường) với ưu tiên
thấp, khi CPU rảnh rang, nên ta không biết chắc một Object sẽ bị hủy diệt
đến bao giờ mới thật sự biến mất. Ta nói nó có nondeterministic
finalization.
Ta có thể ép CLR nhặt rác lập tức bằng
code:
Tuy nhiên, ta chỉ làm việc ấy khi kẹt
quá thôi. Tốt hơn, ta duyệt lại design của mình để cho phép các Objects hết
xài có thể ngồi chơi trong bộ nhớ chờ đến lúc được hủy diệt.
Dùng Dispose MethodNếu ta có một Object
dùng nhiều tài nguyên (resources) như bộ nhớ, database connection, file
handle,.v.v. và ta cần phải thả các tài nguyên ra ngay sau khi Object không
còn hoạt động nữa, ta cần implement một Interface tên
IDisposable với Implements keyword như sau:
Public Class TheClass Implements IDisposable
| Bạn phải viết code cho Sub Dispose
giống như sau:
Private Sub Dispose() Implements IDisposable.Dispose ' Viết clean up code ở đây để thả các tài nguyên ra End Sub
| Sau đó bạn vẫn phải viết code cho
Client để nó gọi Dispose Method trong IDisposable interface. Bạn cần phải
dùng CType để cast Object Class khi gọi Dispose.
Dim objObject As New TheClass() CType (objObject, IDisposable).Dispose()
| Để lấy đi Reference đến một
Object (gọi là Dereference Object) bạn có thể dùng:
Để ý là ta không có dùng keyword Set
như trong VB6. Nhớ là sau khi statement trên được executed thì myObject
không biến mất ngay nhưng nó đợi Garbage Collector đến giải quyết.
Thừa kếThừa kế (Inheritance) là khả
năng của một Class đạt được interface (giao diện) và
behaviours (tánh tình) của một Class có sẵn. Cái quá trình để làm nên
việc ấy được gọi là Subclassing. Khi ta tạo ra một Class mới thừa kế
cả interface lẫn behaviours từ một Class có sẵn là chúng ta đã tạo ra một
subclass của Class nguyên thủy. Người ta nói đó là một mối liên hệ
is-a (là một), ý nói Class mới là một loại Class nguyên
thủy.
Ta phân biệt mối liên hệ is-a với mối liên hệ
has-a (có một). Trong mối liên hệ has-a, Object chủ có thể làm chủ
một hay nhiều Objects tớ, nhưng Object tớ là một loại có thể hoàn toàn khác
với Object chủ.
Để biểu diễn đặc tính Inheritance ta hãy xét trường
hợp một công ty cung cấp Sản phẩm và Dịch vụ. Ta có thể code
một Class cho Sản phẩm (ProductLine) và một Class cho Dịch vụ
(ServiceLine) , riêng rẽ nhau. Nhưng vì thấy chúng có nhiều điểm
tương đồng nên ta sẽ code một Class gọi là Món hàng (LineItem), rồi
inherit từ LineItem ra ProductLine và ServiceLine.
LineItem có các
properties ID, Item, Price (giá) và Quantity (số lượng). Nó cũng có một
Public Function để cho Amount (số tiền).
Public Class LineItem Private mintID As Integer Private mstrItem As String Private msngPrice As Single Private mintQuantity As Integer
Public Property ID() As Integer Get Return mintID End Get Set (ByVal Value As Integer) mintID = Value End Set End Property
Public Property Item() As String Get Return mstrItem End Get Set (ByVal Value As String) mstrItem = Value End Set End Property
Public Property Price() As Single Get Return msngPrice End Get Set (ByVal Value As Single) msngPrice = Value End Set End Property
Public Property Quantity() As Integer Get Return mintQuantity End Get Set (ByVal Value As Integer) mintQuantity = Value End Set End Property
Public Function Amount() As Single Return mintQuantity * msngPrice End Function
End Class
| Để tạo Class ProductLine từ Class
LineItem ta phải dùng Inherits keyword. Mỗi Object ProductLine là
một Object LineItem với ProductID và Description. ProductID của
ProductLine được pass vào Sub New lúc instantiate Object ProductLine. Còn
Description là một ReadOnly property của ProductLine. Ta có thể code Class
ProductLine như sau:
Public Class ProductLine Inherits LineItem
Private mstrDescription As String
Public ReadOnly Property Description() As String Get Return mstrDescription End Get End Property
Public Sub New(ByVal ProductID As String) Item = ProductID mstrDescription = "No description yet" ' Default description ' Viết code ở đây để đọc chi tiết của Product từ Database ' trong đó có thể có Description của Product End Sub End Class
| Statement Inherits LineItem
khiến ProductLine thừa kế mọi interface và behaviours của LineItem. Do đó ta
có thể code một Sub BtnProduct_Click để hiển thị chi tiết của
ProductLine trong một Listbox như sau:
Protected Sub BtnProduct_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnProduct.Click Dim pl As ProductLine pl = New ProductLine("P1234") ListBox1.Items.Add("ProductItem:" & pl.Item) ListBox1.Items.Add("Description: $" & pl.Description) End Sub
| Trong code bên trên ta dùng cả
property Item của Class LineItem lẫn property Description của Class
ProductLine. Cả hai đều là property của ProductLine vì nó là một SubClass
của LineItem.
Giống như vậy, một ServiceLine có thể có ghi ngày giờ
cung cấp service. Ta code Class ServiceLine như sau:
Public Class ServiceLine Inherits LineItem
Private mdtDateProvided As Date
Public Sub New() ' Make 1 as default number of services of this kind for invoice Quantity = 1 End Sub
Public Property DateProvided() As Date Get Return mdtDateProvided End Get Set (ByVal Value As Date) mdtDateProvided = Value End Set End Property
End Class
| Một lần nữa ta dùng Statement
Inherits để nói rằng ServiceLine là một SubClass của LineItem. Ta thêm
property DateProvided vào interface thừa kế từ Class
LineItem.
Bạn có thể Download source
code của program nầy tại đây.
|
|
|
Thừa kế Textbox để đánh chữ Việt Unicode (04-09-2009 | 08:41:04 PM)
Multithreaded Winsock (04-09-2009 | 08:40:24 PM)
Dùng Unicode chữ Việt trong .NET (04-09-2009 | 08:37:43 PM)
Bài 15 - DataGrid (phần III) (04-09-2009 | 08:30:15 PM)
Bài 14 - DataGrid (phần II) (04-09-2009 | 08:30:00 PM)
|
|
|
|
|
|