Lợi thế của việc sử dụng các lớp thay vì chỉ các chương trình con là các lớp tạo ra mức trừu tượng cho phép bạn viết mã sạch hơn. Phải thừa nhận rằng, nếu bạn chưa bao giờ sử dụng các lớp học trước đây trong VBA, có một đường cong học tập, nhưng tôi tin rằng nó chắc chắn đáng để dành thời gian để tìm ra nó.
Một chỉ báo chính mà bạn nên chuyển sang lớp học là nếu bạn liên tục thêm thông số vào các hàm và chương trình con của mình. Trong trường hợp này, nó hầu như luôn luôn tốt nhất để sử dụng các lớp học.
tôi đã sao chép một lời giải thích của các tầng lớp từ one of my previous Stack Overflow answers:
Dưới đây là một ví dụ dài về cách sử dụng một lớp học có thể giúp bạn. Mặc dù ví dụ này là dài nhưng nó sẽ cho bạn thấy một vài nguyên tắc của lập trình hướng đối tượng thực sự có thể giúp bạn làm sạch mã của bạn như thế nào.
Trong trình chỉnh sửa VBA, hãy truy cập Insert > Class Module
. Trong cửa sổ Properties (dưới cùng bên trái của màn hình theo mặc định), thay đổi tên của module thành WorkLogItem
. Thêm mã sau vào lớp học:
Option Explicit
Private pTaskID As Long
Private pPersonName As String
Private pHoursWorked As Double
Public Property Get TaskID() As Long
TaskID = pTaskID
End Property
Public Property Let TaskID(lTaskID As Long)
pTaskID = lTaskID
End Property
Public Property Get PersonName() As String
PersonName = pPersonName
End Property
Public Property Let PersonName(lPersonName As String)
pPersonName = lPersonName
End Property
Public Property Get HoursWorked() As Double
HoursWorked = pHoursWorked
End Property
Public Property Let HoursWorked(lHoursWorked As Double)
pHoursWorked = lHoursWorked
End Property
Mã trên sẽ cung cấp cho chúng tôi đối tượng mạnh mẽ dành riêng cho dữ liệu mà chúng tôi đang làm việc. Khi bạn sử dụng mảng nhiều thứ nguyên để lưu trữ dữ liệu của mình, mã của bạn tương tự như sau: arr(1,1)
là ID, arr(1,2)
là Tên người dùng và arr(1,3)
là HoursWorked. Sử dụng cú pháp đó, thật khó để biết cái gì là gì. Giả sử bạn vẫn tải các đối tượng của bạn vào một mảng, nhưng thay vào đó hãy sử dụng WorkLogItem
mà chúng tôi đã tạo ở trên. Tên này, bạn sẽ có thể làm arr(1).PersonName
để lấy tên của người đó. Điều đó làm cho mã của bạn dễ đọc hơn nhiều.
Hãy tiếp tục di chuyển với ví dụ này. Thay vì lưu trữ các đối tượng trong mảng, chúng tôi sẽ thử sử dụng collection
.
Tiếp theo, thêm mô-đun lớp mới và gọi số ProcessWorkLog
. Đặt mã sau đây vào đó:
Option Explicit
Private pWorkLogItems As Collection
Public Property Get WorkLogItems() As Collection
Set WorkLogItems = pWorkLogItems
End Property
Public Property Set WorkLogItems(lWorkLogItem As Collection)
Set pWorkLogItems = lWorkLogItem
End Property
Function GetHoursWorked(strPersonName As String) As Double
On Error GoTo Handle_Errors
Dim wli As WorkLogItem
Dim doubleTotal As Double
doubleTotal = 0
For Each wli In WorkLogItems
If strPersonName = wli.PersonName Then
doubleTotal = doubleTotal + wli.HoursWorked
End If
Next wli
Exit_Here:
GetHoursWorked = doubleTotal
Exit Function
Handle_Errors:
'You will probably want to catch the error that will '
'occur if WorkLogItems has not been set '
Resume Exit_Here
End Function
Lớp trên sẽ được sử dụng để "làm điều gì đó" với colleciton WorkLogItem
. Ban đầu, chúng tôi chỉ thiết lập để đếm tổng số giờ làm việc. Hãy kiểm tra mã chúng tôi đã viết.Tạo một Module mới (không phải là một mô-đun lớp lần này, chỉ là một mô-đun "thông thường"). Dán đoạn mã sau trong module:
Option Explicit
Function PopulateArray() As Collection
Dim clnWlis As Collection
Dim wli As WorkLogItem
'Put some data in the collection'
Set clnWlis = New Collection
Set wli = New WorkLogItem
wli.TaskID = 1
wli.PersonName = "Fred"
wli.HoursWorked = 4.5
clnWlis.Add wli
Set wli = New WorkLogItem
wli.TaskID = 2
wli.PersonName = "Sally"
wli.HoursWorked = 3
clnWlis.Add wli
Set wli = New WorkLogItem
wli.TaskID = 3
wli.PersonName = "Fred"
wli.HoursWorked = 2.5
clnWlis.Add wli
Set PopulateArray = clnWlis
End Function
Sub TestGetHoursWorked()
Dim pwl As ProcessWorkLog
Dim arrWli() As WorkLogItem
Set pwl = New ProcessWorkLog
Set pwl.WorkLogItems = PopulateArray()
Debug.Print pwl.GetHoursWorked("Fred")
End Sub
Trong đoạn mã trên, PopulateArray()
chỉ đơn giản là tạo ra một bộ sưu tập của WorkLogItem
. Trong mã thực của bạn, bạn có thể tạo lớp để phân tích các trang tính Excel hoặc các đối tượng dữ liệu của bạn để điền vào một bộ sưu tập hoặc một mảng.
Mã TestGetHoursWorked()
chỉ đơn giản là minh họa cách các lớp được sử dụng. Bạn nhận thấy rằng ProcessWorkLog
được khởi tạo như một đối tượng. Sau khi nó được khởi tạo, một bộ sưu tập của WorkLogItem
trở thành một phần của đối tượng pwl
. Bạn nhận thấy điều này trong dòng Set pwl.WorkLogItems = PopulateArray()
. Tiếp theo, chúng ta chỉ cần gọi hàm mà chúng ta đã viết có tác dụng lên bộ sưu tập WorkLogItems
.
Tại sao điều này hữu ích?
Giả sử thay đổi dữ liệu của bạn và bạn muốn thêm phương thức mới. Giả sử WorkLogItem
của bạn hiện bao gồm một trường cho HoursOnBreak
và bạn muốn thêm một phương thức mới để tính toán.
Tất cả bạn cần làm là thêm một tài sản để WorkLogItem
như vậy:
Private pHoursOnBreak As Double
Public Property Get HoursOnBreak() As Double
HoursOnBreak = pHoursOnBreak
End Property
Public Property Let HoursOnBreak(lHoursOnBreak As Double)
pHoursOnBreak = lHoursOnBreak
End Property
Tất nhiên, bạn sẽ cần phải thay đổi phương thức của bạn cho Populating sưu tập của bạn (phương pháp mẫu Tôi đã từng là PopulateArray()
, nhưng bạn có lẽ nên có một lớp riêng biệt chỉ cho việc này). Sau đó, bạn chỉ cần thêm phương pháp mới của bạn đến lớp ProcessWorkLog
của bạn:
Function GetHoursOnBreak(strPersonName As String) As Double
'Code to get hours on break
End Function
Bây giờ, nếu chúng ta muốn cập nhật phương thức của chúng tôi TestGetHoursWorked()
để trả về kết quả của GetHoursOnBreak
, tất cả chúng ta sẽ phải làm như thêm dòng sau:
Debug.Print pwl.GetHoursOnBreak("Fred")
Nếu bạn chuyển qua một mảng giá trị đại diện cho dữ liệu của mình, bạn sẽ phải tìm mọi vị trí trong mã nơi bạn đã sử dụng mảng và sau đó cập nhật nó cho phù hợp. Thay vào đó, nếu bạn sử dụng các lớp (và các đối tượng instantiated của chúng), bạn có thể dễ dàng cập nhật mã của mình để làm việc với các thay đổi. Ngoài ra, khi bạn cho phép lớp được tiêu thụ theo nhiều cách (có lẽ một hàm chỉ cần 4 thuộc tính đối tượng trong khi một hàm khác sẽ cần 6), chúng vẫn có thể tham chiếu cùng một đối tượng. Điều này giúp bạn không có nhiều mảng cho các loại hàm khác nhau.
Để đọc thêm, tôi sẽ cao khuyên bạn nên nhận bản sao VBA Developer's Handbook, 2nd edition. Cuốn sách có đầy đủ các ví dụ tuyệt vời và thực hành tốt nhất và tấn mã mẫu. Nếu bạn đang đầu tư nhiều thời gian vào VBA cho một dự án nghiêm túc, bạn cũng nên dành thời gian để xem cuốn sách này.
+1, Câu trả lời tuyệt vời. Rõ ràng, sắc nét và rất hữu ích cho tất cả mọi người. –
+1 cho Sổ tay của Nhà phát triển VBA! –
Vẫn hữu ích 5 năm sau, cảm ơn Ben! +1 từ tôi. – FreeMan