Khóa học
Lập trình hướng đối tượng (OOP) là một mô hình lập trình trong đó phần mềm được thiết kế xoay quanh dữ liệu hoặc đối tượng thay vì chỉ dùng hàm. Một phương thức về bản chất là một hàm, nhưng được nói tới trong ngữ cảnh OOP. Gọi là hướng đối tượng vì mọi xử lý đều xoay quanh các đối tượng và trường dữ liệu. Mỗi đối tượng có các thuộc tính và hành vi khác nhau.
Trong lập trình hướng đối tượng, toàn bộ chương trình có thể được chia thành các lớp khác nhau để dễ hiểu quá trình thực thi. R là một ngôn ngữ lập trình hàm, và OOP sẽ giúp quản lý các bài toán hệ thống lớn. OOP thường được dùng để quản lý ứng dụng GUI, đặc biệt là ứng dụng web. OOP phù hợp để xây dựng công cụ phục vụ phân tích dữ liệu nhưng không phù hợp cho bản thân việc phân tích dữ liệu.
Hệ thống OOP
Chủ yếu có hai hệ thống OOP chính, mô tả dưới đây:
- Lớp S3: Cho phép bạn overload các hàm.
- Lớp S4: Cho phép bạn ràng buộc dữ liệu vì việc gỡ lỗi chương trình khá khó.
Lưu ý: Các lớp này sẽ được bàn chi tiết ở phần sau.
Đối tượng trong R
Đối tượng là thể hiện (instance) của lớp. Đồng thời, mọi thứ trong R đều là đối tượng; để tìm hiểu thêm hãy xem Kiểu dữ liệu trong R. Chúng cũng có thể có các thuộc tính như class, attributes, dimnnames, names, v.v.
Ví dụ, đối tượng được gán giá trị bằng <-, hãy xem đoạn mã sau trong đó 'a1' và 'a2' là biến được gán giá trị số.
a1 <- 10
a2 <- 20
Một đối tượng có thể được gán một tập số, trong đó 'a3' là đối tượng chứa một vector các số khác nhau.
a3 <- c(10,20,30)
Ở đây c gom các số 10, 20, 30 vào một vector.
Hãy lấy ví dụ đời thực như học sinh, có các thuộc tính tên, tuổi, lớp và giới tính; giáo viên thì có tên, tuổi và giới tính.
st_name <- "andrew"
st_age <- 16
st_class <- 10
st_gender <- "male"
t_name <- "angelina"
t_age <- 26
t_gender <- "female"
student <- c(st_name, st_age, st_class, st_gender)
teacher <- c(t_name, t_age, t_gender)
print(student)
print(teacher)
[1] "andrew" "16" "10" "male"
[1] "angelina" "26" "female"
Đoạn mã trên cho kết quả sau:
"andrew" "16" "10" "male"
"angelina" "26" "female"
Trong đoạn mã trên, bạn thấy ví dụ có các loại đối tượng khác nhau. Đối tượng 'student' và 'teacher', còn gọi là biến, giữ kiểu 'character' và 'double'.
Lớp trong R
Lớp là bản thiết kế giúp tạo ra đối tượng và chứa biến thành viên cùng các thuộc tính của nó.
Như đã thảo luận ở phần trước, R có hai lớp là S3 và S4.
Lớp S3
Các lớp này giúp overload hàm bằng cách tách chúng thành generic và methods.
functions = generic + methods
S3 rất khác so với các ngôn ngữ lập trình khác như C#, Java, v.v. Vì việc triển khai rất đơn giản, nó chỉ dùng đối số đầu tiên để điều phối (dispatch). Do đó, từ góc nhìn lập trình viên, bạn không cần quá nhiều kiến thức để dùng.
S3 hoạt động bằng cách định nghĩa quy ước đặt tên chặt chẽ theo dạng generic.ch_class.
generic.class
Các đối số của method nên chứa các đối số của generic, và method nên bao gồm ...arg.
Xây dựng kèm ví dụ về lớp S3
Bạn sẽ được minh họa cách xây dựng một lớp S3 trong ví dụ sau, thể hiện việc tạo một list nơi các thành phần được truyền vào cùng tên lớp phù hợp, sau đó in ra kết quả.
Ví dụ sau cho thấy 'studentBio' chứa một list, trong đó các thành phần được truyền vào dưới dạng list gồm 'student_name', 'student_age' và 'student_contact'. Lớp có tên 'Student Info', và 'studentBio' là lớp mới tạo, các giá trị của nó được hiển thị bên dưới.
studentBio <- list(studentName = "Harry Potter", studentAge = 19, studentContact="London")
class(studentBio) <- "StudentInfo"
studentBio
$studentName
[1] "Harry Potter"
$studentAge
[1] 19
$studentContact
[1] "London"
attr(,"class")
[1] "StudentInfo"
Đoạn mã trên cho kết quả như dưới đây:
$studentName
"Harry Potter"
$studentAge
19
$studentContact
"London"
attr(,"class")
"StudentInfo"
Nếu bạn chưa thoải mái khi viết hàm trong R, hãy đọc Hướng dẫn sử dụng hàm trong R!
Tạo generic method của riêng bạn trong S3
Bạn sẽ triển khai hàm generic của mình bên dưới bằng đoạn mã sau.
Đoạn mã dưới đây cho thấy hàm generic gọi là 'contact' nơi hàm nhận đối tượng được truyền vào. Đồng thời, 'UseMethod' được dùng với hàm generic 'contact' để thực hiện 'dispatching' method, tức quá trình kết quả thay đổi dựa trên các đối số truyền vào.
contact <- function(object) {
UseMethod("contact")
}
Hãy tạo một method cho lớp cụ thể mà bạn đã tạo trước đó tên 'StudentInfo'. Method 'contact' theo sau là dấu chấm cùng tên lớp 'StudentInfo' được dùng; thân hàm truy cập thuộc tính 'studentContact' bằng '$'.
contact.StudentInfo <- function(object) {
cat("Your contact is", object$studentContact, "\n")
}
contact(studentBio)
Your contact is London
Đoạn mã trên dùng object$studentContact, trong đó đối tượng được truyền làm đối số cho hàm, kèm '$' để truy cập thuộc tính 'studentContact', cho ra kết quả như dưới đây.
Your contact is London
Lớp S4
Lớp S4 nghiêm ngặt, theo quy ước và gần gũi hơn với các khái niệm hướng đối tượng. Các lớp được biểu diễn bởi các định nghĩa lớp chính thức của S4. Cụ thể hơn, S4 có hàm setter và getter cho methods và generics. So với lớp S3, S4 hỗ trợ multiple dispatch.
Hãy xem các lớp của R đã bàn ở trên bằng cách tạo chúng và thảo luận qua ví dụ.
Một lớp S4 được định nghĩa bằng hàm set class.
setClass()
Xây dựng kèm ví dụ về lớp S4
Như đã đề cập, lớp S4 được định nghĩa bằng phương thức setClass(). Bạn sẽ dùng setClass() để tạo và định nghĩa lớp S4. Chúng ta sẽ dùng một thủ tục phụ để xác minh dữ liệu nhất quán (validation) và đồng thời đặt giá trị mặc định (nguyên mẫu).
Sau đây là mã để định nghĩa lớp và các slot của nó:
Đoạn sau được dùng để định nghĩa một lớp, còn gọi là 'prototype', trong đó các slot được định nghĩa: tên lớp là 'employee', name là character, id là numeric, và contact là character.
setClass("employee", slots=list(name="character", id="numeric", contact="character"))
Đoạn mã sau có thể tạo các thể hiện hoặc đối tượng cụ thể của S4.
Hãy tạo một đối tượng bằng 'new' với tên lớp bên trong là 'employee' và điền giá trị cho các slot như name, id và contact.
obj <- new("employee",name="Steven", id=1002, contact="West Avenue")
obj
An object of class "employee"
Slot "name":
[1] "Steven"
Slot "id":
[1] 1002
Slot "contact":
[1] "West Avenue"
An object of class "employee"
Slot "name":
"Steven"
Slot "id":
1002
Slot "contact":
"West Avenue"
Kết quả trên cho thấy đối tượng được tạo thuộc lớp "employee" và Slot "name" có giá trị "Steven" cùng Slot "id" giá trị 1002 và Slot "contact" giá trị "West Avenue".
Hàm và lệnh
Để kiểm tra một đối tượng có phải đối tượng S4 hay không có thể dùng hai lệnh sau:
Lệnh 'is.object(obj)' kiểm tra một biến hoặc thể hiện có tham chiếu tới một đối tượng hay không.
is.object(obj)
TRUE
Đoạn mã trên cho kết quả như dưới đây:
TRUE
Lệnh 'is.S4(obj)' kiểm tra một biến hoặc thể hiện có phải đối tượng S4 hay không.
isS4(obj)
TRUE
Đoạn mã trên cho kết quả như dưới đây:
TRUE
Truy cập và sửa giá trị slot
Truy cập slot
Slot có thể được truy cập bằng ký hiệu "@" thay vì "$".
'obj@name' được dùng với tên đối tượng cùng tên slot để truy cập tên 'Steven' và tương tự với 'obj@id'.
obj@name
obj@id
'Steven'
1002
Đoạn mã trên cho kết quả:
'Steven'
1002
Sửa slot
Hãy sửa giá trị slot chỉ bằng toán tử gán ("<-") khi 'obj@contact' được gán giá trị mới là "North Avenue".
obj@contact <- "North Avenue"
obj
An object of class "employee"
Slot "name":
[1] "Steven"
Slot "id":
[1] 1002
Slot "contact":
[1] "North Avenue"
Đoạn mã trên cho kết quả:
An object of class "employee"
Slot "name":
"Steven"
Slot "id":
1002
Slot "contact":
"North Avenue"
Kết quả trên cho thấy Slot "contact" đã thay đổi giá trị từ "West Avenue" thành "North Avenue".
Cách khác, có thể dùng 'slot()' để thay đổi giá trị.
'slot(obj, "id")' biểu thị giá trị slot "id" sẽ được thay đổi bằng cách gán 1004, và kết quả được in với 'obj'.
slot(obj,"id") <- 1004
obj
An object of class "employee"
Slot "name":
[1] "Steven"
Slot "id":
[1] 1004
Slot "contact":
[1] "North Avenue"
An object of class "employee"
Slot "name":
"Steven"
Slot "id":
1004
Slot "contact":
"North Avenue"
Kết quả trên cho thấy Slot "id" đã thay đổi giá trị từ 1002 thành 1004.
Tạo generic method của riêng bạn trong S4
Hãy tạo một hàm giúp in kết quả theo nhu cầu của chúng ta, trong đó dùng 'setMethod()' và hàm generic 'show()'. Đồng thời, giá trị của tất cả các slot được truy cập bằng '@' và tên của chúng được in ra. Cuối cùng, kết quả thu được với 'obj'.
setMethod("show",
"employee",
function(object) {
cat("Name:",object@name, "\n")
cat("Id:",object@id, "\n")
cat("Contact:", object@contact, "\n")
}
)
obj
Name: Steven
Id: 1004
Contact: North Avenue
Name: Steven
Id: 1004
Contact: North Avenue
Kết quả trên cho thấy các mục được in ra theo tên Slot cùng giá trị Slot tương ứng.
Chúc mừng
Chúc mừng bạn đã hoàn thành bài hướng dẫn này!
Trong hướng dẫn này, bạn đã tìm hiểu về Lập trình Hướng Đối Tượng (OOP) cùng các đối tượng trong R, các lớp như S3 và S4, cách xây dựng, tạo hàm generic kèm ví dụ và nhiều nội dung khác.
Nếu bạn muốn học thêm về R, hãy xem các khóa học của DataCamp: