Bài 26-Lập trình hướng đối tượng trong Kotlin – phần 5


Trong phần này Tui sẽ trình bày các kiến thức liên quan tới Kế Thừa trong lập trình Hướng đối tượng. Để học tốt bài này thì bắt buộc bạn phải đả thông kinh mạch các bài:

Bài 22-Lập trình hướng đối tượng trong Kotlin – phần 1

Bài 23-Lập trình hướng đối tượng trong Kotlin – phần 2

Bài 24-Lập trình hướng đối tượng trong Kotlin – phần 3

Bài 25-Lập trình hướng đối tượng trong Kotlin – phần 4

Trước khi đi vào kỹ thuật cài đặt Kế Thừa trong Kotlin, Tui điểm sơ sơ 1 xíu về Khái Niệm Kế Thừa.

Kế thừa là gì?

Kế thừa bạn có thể hiểu nôm na là Sự TÁI SỬ DỤNG lại mã nguồn cũ, có thể mở rộng thêm mã lệnh mới từ những thứ đã tồn tại, giúp nâng cao hiệu suất lập trình.

Thường các đối tượng có cùng chung một số đặc điểm, hành vi được nhóm lại với nhau.

Ví dụ:

  • Xe đạp
  • Xe máy
  • Xe hơi
  • Xe tải

các xe này có một số đặc điểm giống nhau đúng ko?

Ta thường thấy mô hình Lớp kế thừa người ta vẽ giống như dưới đây:

Hay Một lớp con có thể là lớp cha của các lớp khác:

Để làm tốt được Kế Thừa thì ta cần biết 2 khái niệm:

Tổng quát hoá: Những đặc điểm chung mà các lớp đều có==>là các lớp Cha

Chuyên biệt hóa: Những đặc điểm riêng chỉ có các lớp con mới có ==>là các lớp Con

Ví dụ: Công ty có 2 loại nhân viên (Nhân Viên Chính Thức và Nhân Viên Thời Vụ):

Thì rõ ràng Nhân viên không kể là Chính thức hay thời vụ thì mọi người đều có mã, tên. Nhưng Nhân viên chính thức và nhân viên thời vụ thì khác nhau ít nhất là cách tính lương. Do đó Lớp Tổng quát Hoát là lớp Nhân Viên vì nó có các đặc điểm chung của Chính Thức và Thời Vụ, Còn các lớp chuyên biệt hóa là: Nhân VIên CHính Thức, Nhân VIên Thời Vụ:Cài đặt Kế thừa trong Kotlin như thế nào?

Ta sẽ viết ví dụ bài Nhân Viên theo hình ở trên. Trong Kotlin, để viết Lớp cho phép kế thừa ta làm như sau:

Lớp Tổng quát hóa (lớp cha) Nhân Viên:


/**
* Created by cafe on 02/06/2017.
*/
open abstract class NhanVien {
protected var ma:Int=0
protected var ten:String=""
public abstract fun tinhLuong(ngayCong:Int):Double
}

Lớp cha NhanVien ở trên là một lớp trừu tượng, khi có phương thức trừu tượng tinhLuong. Vấn đề là làm sao biết được nên khai báo nó là phương thức trừu tượng? Ta hiểu nôm na như sau: Mọi nhân viên điều tính lương, nhưng ngay thời điểm này không biết tính lương cho nhân viên nào, mà không biết tính cụ thể cho ai thì khai báo nó là trừu tượng (tuy không biết là tinhLuong cho đối tượng nào nhưng chắc chắn nó phả có tinhLuong). Với abstract hay interface thì các hàm trừu tượng nó giống như là các luật, các mẫu đưa ra và yêu cầu các lớp con kế thừa phải tuân thủ theo (override lại toàn bộ).

Một điều cần lưu ý nữa là Nếu muốn các lớp khác có thể kế thừa từ lớp này thì bắt buộc ta phải thêm từ khóa open đằng trước khai báo lớp như mẫu code ở trên.

Bây giờ ta tạo 1 lớp NhanVienChinhThuc kế thừa từ lớp NhanVien như sau:

Bạn thấy ta dùng dấu 2 chấm (:) để kế thừa nhé, nhìn vào hình trên là ta biết cách viết NhanVienChinhThuc kế thừa từ NhanVien phải viết như thế nào.

Ở trên bạn thấy nó báo lỗi màu đỏ, thực ra là do lớp NhanVien là lớp trừu tựu. Thì các lớp con kế thừa từ lớp trừu tượng bắt buộc phải Override lại toàn bộ phương thức trừu tượng của lớp cha. IntelliJ IDEA hỗ trợ chúng ta công cụ overrid này rất nhanh chóng. Đó là ngày chỗ báo lỗi bạn nhấn tổ hợp phím Alt+Enter nó sẽ xuất hiện ra màn hình có dòng Implement members như hình trên, ta chọn nó rồi nhấn Enter, màn hình Implement Members sẽ xuất hiện như dưới đây:

Ta chọn các phương thức trừu tượng của lớp cha rồi bấm OK, nó sẽ tự động phát sinh Coding như sau:


/**
* Created by cafe on 02/06/2017.
*/
class NhanVienChinhThuc:NhanVien() {
override fun tinhLuong(ngayCong: Int): Double {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}

Giả sử rằng nhân viên chính thức có lương: Nếu NgayCong>=22 thì lương là 10 triệu, còn <22 ngày thì lương 10 triệu – mỗi ngày nghỉ mất 500 nghìn, ta sửa lại coding như sau:


/**
* Created by cafe on 02/06/2017.
*/
class NhanVienChinhThuc:NhanVien() {
override fun tinhLuong(ngayCong: Int): Double {
if(ngayCong>=22)
return 10000000.0
return 10000000.0-500000*(22-ngayCong)
}
}

Tương tự như vậy ta Tạo lớp NhanVienThoiVu kế thừa từ NhanVien. Và lương  của Nhân viên thời vụ là 150k*số ngày công:


/**
* Created by cafe on 02/06/2017.
*/
class NhanVienThoiVu:NhanVien() {
override fun tinhLuong(ngayCong: Int): Double {
return ngayCong*150000.0
}

}

Cách sử dụng các lớp Kế thừa trong Kotlin như thế nào?

Tạo một tập tin Kotlin để thử nghiệm


/**
* Created by cafe on 02/06/2017.
*/
fun main(args: Array<String>) {
var an=NhanVienChinhThuc()
var binh=NhanVienThoiVu()
var luongAn=an.tinhLuong(20)
println("Lương của An="+luongAn)
var luongBinh=binh.tinhLuong(3)
println("Lương của Bình="+luongBinh)
}

Kết quả khi chạy ta thấy:

Lương của An=9000000.0
Lương của Bình=450000.0

Ở trên các bạn thấy Tui hay nhắc tới Override, vậy nó là cái gì? (bạn đã từng học Overloading đúng ko), bạn có thể hiểu nôm na Overriding Method như sau:

  • Trong một tập các lớp có mối quan hệ huyết thống có các phương thức giống signature y xì (nội dung phương thức khác nhau)
  • Overriding methods giúp lập trình viên có thể định nghĩa cách hành xử khác nhau ứng với các đối tượng khác nhau nhưng cùng sử dụng một tên phương thức.
  • Ví dụ: Nhân viên chính thức và Nhân viên thời vụ đều có phương thức là Tính Lương, tuy nhiên cách thức tính lương của 2 đối tượng này sẽ khác nhau.

Bạn tự so sánh sự khác nhau giữa Overloading Method và Overriding Method.

Còn cách kế thừa nào khác trong Kotlin không?

Trong Kotlin còn có thể dùng Interface để Kế thừa (implements), Interface không phải là GUI mà là tập các giao ước (các luật, các Rule) khi các lớp con implents(hay gọi là kế thừa ) thì phải định nghĩa lại toàn bộ các phương thức này.

Giả sử ta có interface:


interface MyInterface {
fun bar()
fun foo() {
// optional body
}
}

Thì khi lớp con kế thừa ta có thể viết như sau:


class Child : MyInterface {
override fun bar() {
// body
}
}

Chúng ta chú ý là với Kotlin kế thừa từ Lớp cũng chỉ cho đơn thừa kế giống như Java , C#. Kế thừa từ Interface cho phép đa thừa kế Interface (đa dẫn xuất), vì vậy đôi khi nó bị conflict nếu như các Interface mà nó kế thừa có các phương thức trừu tượng trùng tên nhau. Trường hợp này Kotlin giải quyết như sau:


interface A {
fun foo() { print("A") }
fun bar()
}
interface B {
fun foo() { print("B") }
fun bar() { print("bar") }
}
class C : A {
override fun bar() { print("bar") }
}
class D : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
override fun bar() {
super<B>.bar()
}
}

Như vậy tới đây Tui đã trình bày xong phần kế thừa trong Kotlin, còn rất nhiều phần khác liên quan tới Kế thừa trong Kotlin, các bạn tự xử nhé (ví dụ như tính đa hình, seal classes). Các bạn chú ý học kỹ, thực hành lại và có gắng hiểu được nó thông qua các ví dụ ở trên nhé. Các bài sau Tui sẽ trình bày về alias và cơ chế gom rác tự động trong Kotlin, các bạn chú ý theo dõi

Các bạn có thể tải source code bài này ở đây: http://www.mediafire.com/file/448pk2x91l1n016/HocOOPPhan5.rar

Hẹn gặp các bạn ở những bài tiếp theo

Chúc các bạn thành công!

Trần Duy Thanh (http://ssoftinc.com/)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: