Bài 34-Đọc JSon tỉ giá hối đoái của Ngân Hàng Đông Á trong Kotlin – Bài 3


Tui đã trình bày kỹ cách sử dụng JSon trong Kotlin ở các bài 32, bài 33 . Tui muốn minh họa thêm một ví dụ cuối cùng về đọc JSon trong Kotlin, trong bài này Tui sẽ coding lấy Tỉ giá hối đoái của Ngân Hàng Đông Á cung cấp:

bạn vào link này để xem Webservice API cung Tỉ giá hối đoái của DongA Bank: http://dongabank.com.vn/exchange/export

Đây là kết quả (nó luôn chính xác và thời gian thực nhé các bạn, hàng ngày Ngân hàng Đông Á luôn cập nhật giá khi có sự thay đổi):

({“items”:[{“type”:”CAD”,”imageurl”:”http:\/\/www.dongabank.com.vn\/images\/flag\/CAD.gif”,”muatienmat”:”16720″,”muack”:”16740″,”bantienmat”:”16930″,”banck”:”16930″},{“type”:”XAU”,”imageurl”:”http:\/\/www.dongabank.com.vn\/images\/flag\/XAU.gif”,”muatienmat”:”3632000″,”muack”:”3621000″,”bantienmat”:”3655000″,”banck”:”3621000″},{“type”:”AUD”,”imageurl”:”http:\/\/www.dongabank.com.vn\/images\/flag\/AUD.gif”,”muatienmat”:”16790″,”muack”:”16800″,”bantienmat”:”16980″,”banck”:”17000″},{“type”:”CHF”,”imageurl”:”http:\/\/www.dongabank.com.vn\/images\/flag\/CHF.gif”,”muatienmat”:”23430″,”muack”:”23450″,”bantienmat”:”23730″,”banck”:”23730″},{“type”:”CNY”,”imageurl”:”http:\/\/www.dongabank.com.vn\/images\/flag\/CNY.gif”,”muatienmat”:”3000″,”muack”:”3000″,”bantienmat”:”3500″,”banck”:”3500″},{“type”:”EUR”,”imageurl”:”http:\/\/www.dongabank.com.vn\/images\/flag\/EUR.gif”,”muatienmat”:”25460″,”muack”:”25480″,”bantienmat”:”25750″,”banck”:”25750″},{“type”:”GBP”,”imageurl”:”http:\/\/www.dongabank.com.vn\/images\/flag\/GBP.gif”,”muatienmat”:”29070″,”muack”:”29110″,”bantienmat”:”29450″,”banck”:”29450″},{“type”:”HKD”,”imageurl”:”http:\/\/www.dongabank.com.vn\/images\/flag\/HKD.gif”,”muatienmat”:”2550″,”muack”:”2900″,”bantienmat”:”2940″,”banck”:”2940″},{“type”:”JPY”,”imageurl”:”http:\/\/www.dongabank.com.vn\/images\/flag\/JPY.gif”,”muatienmat”:”204.3″,”muack”:”204.6″,”bantienmat”:”206.7″,”banck”:”206.7″},{“type”:”NZD”,”imageurl”:”http:\/\/www.dongabank.com.vn\/images\/flag\/NZD.gif”,”muatienmat”:””,”muack”:”16120″,”bantienmat”:””,”banck”:”16320″},{“type”:”PNJ_DAB”,”imageurl”:”http:\/\/www.dongabank.com.vn\/images\/flag\/PNJ_DAB.gif”,”muatienmat”:”3495000″,”muack”:”3495000″,”bantienmat”:”3545000″,”banck”:”3545000″},{“type”:”SGD”,”imageurl”:”http:\/\/www.dongabank.com.vn\/images\/flag\/SGD.gif”,”muatienmat”:”16320″,”muack”:”16340″,”bantienmat”:”16540″,”banck”:”16540″},{“type”:”THB”,”imageurl”:”http:\/\/www.dongabank.com.vn\/images\/flag\/THB.gif”,”muatienmat”:”595″,”muack”:”625″,”bantienmat”:”655″,”banck”:”655″},{“type”:”USD”,”imageurl”:”http:\/\/www.dongabank.com.vn\/images\/flag\/USD.gif”,”muatienmat”:”22680″,”muack”:”22680″,”bantienmat”:”22750″,”banck”:”22750″}]})

Như chúng ta đã học ở những bài lý thuyết Json thì đây không phải là cấu trúc Json. Vì cấu trúc JSon chỉ chấp nhận 2 loại đó là: Dữ liệu được để trong {} hoặc được để trong [] . Còn ở đây Ngân Hàng Đông Á lại để () ở ngoài. Do đó lúc đọc dữ liệu về ta chỉ cần Remove 2 ký tự này đi là xong.

Tiếp tục phân tích cấu trúc của Json ở trên:

Rõ ràng ở ngoài là 1 đối tượng JSonObject, bên trong nó có một JSonArray đặt tên là items. Mỗi đối tượng trong mảng Items có 6 thuộc tính như ở trên.

Bây giờ ta tạo một Project, và đưa thư viện gson-2.8.1.jar như các bài trước vào (bạn tự làm vì Tui đã hướng dẫn rất chi tiết ở các bài trước ), rồi tiến hành tạo các lớp sau:

Lớp Item để lưu trữ các dữ liệu bên trong mảng items (chú ý là các thuộc tính phải copy paste y xì từ dữ liệu JSon mà Đông Á Bank cung cấp):


/**
* Created by cafe on 03/06/2017.
*/
class Item {
var type:String=""
var imageurl:String=""
var muatienmat:String=""
var muack:String=""
var bantienmat:String=""
var banck:String=""
override fun toString(): String {
return "Mã Tiền Tệ : "+type+"\n"+
"Mua tiền mặt :"+muatienmat+"\n"+
"Bán tiền mặt :"+bantienmat+"\n"+
"Mua chuyển khoản :"+muack+"\n"+
"Bán chuyển khoản :"+banck+"\n"+
"Hình đại diện :"+imageurl+"\n"
}
}

Tiếp theo tạo 1 Lớp tỉ giá để lưu trữ mảng items

Các bạn cần nhớ là với GSon nó không quan tâm tên Lớp là gì(đặt tên gì cũng được), nó quan tâm tên thuộc tính (phải đặt chính xác như dữ liệu Json cũng cấp)


/**
* Created by cafe on 03/06/2017.
*/
class TiGia {
var items:MutableList<Item> = mutableListOf()
}

Cuối cùng tạo hàm main để kiểm tra lấy dữ liệu từ Ngân Hàng Đông Á, chú ý ta dùng HttpURLConnection để lấy dữ liệu từ Webservice API mà Đông Á Cung cấp.:


import com.google.gson.Gson
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL

/**
* Created by cafe on 03/06/2017.
*/
fun main(args: Array<String>) {
var url:URL=URL("http://dongabank.com.vn/exchange/export")
var connection:HttpURLConnection= url.openConnection() as HttpURLConnection
var isr:InputStreamReader= InputStreamReader(connection.inputStream,"UTF-8")
var br:BufferedReader=BufferedReader(isr)
var s= br.readText()
br.close()
isr.close()
s=s.replace("(","")
s=s.replace(")","")
var gs:Gson= Gson()
var dstg:TiGia=gs.fromJson<TiGia>(s,TiGia::class.java)
for (item in dstg.items)
{
println(item)
println("-------------------------------")
}
}

Khi chạy hàm main ở trên thì ta có kết quả sau:

Mã Tiền Tệ : CAD
Mua tiền mặt :16720
Bán tiền mặt :16930
Mua chuyển khoản :16740
Bán chuyển khoản :16930
Hình đại diện :http://www.dongabank.com.vn/images/flag/CAD.gif——————————-
Mã Tiền Tệ : XAU
Mua tiền mặt :3632000
Bán tiền mặt :3655000
Mua chuyển khoản :3621000
Bán chuyển khoản :3621000
Hình đại diện :http://www.dongabank.com.vn/images/flag/XAU.gif——————————-
Mã Tiền Tệ : AUD
Mua tiền mặt :16790
Bán tiền mặt :16980
Mua chuyển khoản :16800
Bán chuyển khoản :17000
Hình đại diện :http://www.dongabank.com.vn/images/flag/AUD.gif

——————————-
Mã Tiền Tệ : CHF
Mua tiền mặt :23430
Bán tiền mặt :23730
Mua chuyển khoản :23450
Bán chuyển khoản :23730
Hình đại diện :http://www.dongabank.com.vn/images/flag/CHF.gif

——————————-
Mã Tiền Tệ : CNY
Mua tiền mặt :3000
Bán tiền mặt :3500
Mua chuyển khoản :3000
Bán chuyển khoản :3500
Hình đại diện :http://www.dongabank.com.vn/images/flag/CNY.gif

——————————-
Mã Tiền Tệ : EUR
Mua tiền mặt :25460
Bán tiền mặt :25750
Mua chuyển khoản :25480
Bán chuyển khoản :25750
Hình đại diện :http://www.dongabank.com.vn/images/flag/EUR.gif

——————————-
Mã Tiền Tệ : GBP
Mua tiền mặt :29070
Bán tiền mặt :29450
Mua chuyển khoản :29110
Bán chuyển khoản :29450
Hình đại diện :http://www.dongabank.com.vn/images/flag/GBP.gif

——————————-
Mã Tiền Tệ : HKD
Mua tiền mặt :2550
Bán tiền mặt :2940
Mua chuyển khoản :2900
Bán chuyển khoản :2940
Hình đại diện :http://www.dongabank.com.vn/images/flag/HKD.gif

——————————-
Mã Tiền Tệ : JPY
Mua tiền mặt :204.3
Bán tiền mặt :206.7
Mua chuyển khoản :204.6
Bán chuyển khoản :206.7
Hình đại diện :http://www.dongabank.com.vn/images/flag/JPY.gif

——————————-
Mã Tiền Tệ : NZD
Mua tiền mặt :
Bán tiền mặt :
Mua chuyển khoản :16120
Bán chuyển khoản :16320
Hình đại diện :http://www.dongabank.com.vn/images/flag/NZD.gif

——————————-
Mã Tiền Tệ : PNJ_DAB
Mua tiền mặt :3495000
Bán tiền mặt :3545000
Mua chuyển khoản :3495000
Bán chuyển khoản :3545000
Hình đại diện :http://www.dongabank.com.vn/images/flag/PNJ_DAB.gif

——————————-
Mã Tiền Tệ : SGD
Mua tiền mặt :16320
Bán tiền mặt :16540
Mua chuyển khoản :16340
Bán chuyển khoản :16540
Hình đại diện :http://www.dongabank.com.vn/images/flag/SGD.gif

——————————-
Mã Tiền Tệ : THB
Mua tiền mặt :595
Bán tiền mặt :655
Mua chuyển khoản :625
Bán chuyển khoản :655
Hình đại diện :http://www.dongabank.com.vn/images/flag/THB.gif

——————————-
Mã Tiền Tệ : USD
Mua tiền mặt :22680
Bán tiền mặt :22750
Mua chuyển khoản :22680
Bán chuyển khoản :22750
Hình đại diện :http://www.dongabank.com.vn/images/flag/USD.gif

——————————-

Như vậy ta đã Ví dụ xong trường hợp đọc JSon từ 1 Webservice, cụ thể là Tỉ giá hối đoái của Ngân Hàng Đông Á, các bạn tự áp dụng vào các dự án cụ thể nhé. Các bài sau Tui sẽ hướng dẫn thiết kế giao diện (GUI) trong Kotlit, các bạn chú ý theo dõi nhé

Các bạn có thể tải source code bài này ở đây: http://www.mediafire.com/file/hghudhgyo53ra8g/HocJsonDongABank.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/)

Bài 33-Xử lý JSon trong Kotlin – Bài 2


Trong bài 32 Tui đã trình bày chi tiết cách sử dụng thư viện GSon để Lưu Kotlin Model thành JSon và Đọc JSon thành Kotlin Model như thế nào. Ở bài này Tui tiếp tục làm thêm một ví dụ phức tạp hơn về JSon trong Kotlin, đó là tạo ra 2 lớp có mối quan hệ Master-Detail, đây là một trong những trường hợp thường gặp nhiều nhất trong quá trình triển khai dự án thật. Cụ thể Tui sẽ bổ sung thêm một Lớp Danh Mục, nó có mối quan hệ với Lớp Sản Phẩm: Một Danh Mục có nhiều Sản phẩm và Một Sản phẩm thuộc về một danh Mục nào đó. Để qua đây chúng ta tìm hiểu xem GSon tạo ra file JSon như thế nào cũng như phục hồi lại Kotlin Model ra sao.

Bài này Tui sẽ đi trực tiếp vào kỹ thuật lập trình luôn, còn lý thuyết các bạn tự xem lại bài 32 nhé.

Lớp Sản Phẩm có cấu trúc như sau:


import java.io.Serializable

/**
* Created by cafe on 03/06/2017.
*/
class SanPham {
var MaSanPham:Int=0
var TenSanPham:String=""
var DonGia:Double=0.0
constructor()
constructor(MaSanPham: Int, TenSanPham: String, DonGia: Double) {
this.MaSanPham = MaSanPham
this.TenSanPham = TenSanPham
this.DonGia = DonGia
}
override fun toString(): String {
return MaSanPham.toString()+"\t"+TenSanPham+"\t"+DonGia
}
}

Cấu trúc của lớp Danh Mục:


import java.io.Serializable

/**
* Created by cafe on 03/06/2017.
*/
class DanhMuc {
var MaDanhMuc:Int=0
var TenDanhMuc:String=""
var SanPhams:MutableList<SanPham> = mutableListOf()
constructor()
constructor(MaDanhMuc: Int, TenDanhMuc: String) {
this.MaDanhMuc = MaDanhMuc
this.TenDanhMuc = TenDanhMuc
}
override fun toString(): String {
var s=""
for (sp in SanPhams)
s+="\t"+sp.toString() + "\n"
var infor="Danh Mục:["+MaDanhMuc.toString()+ "\t"+TenDanhMuc+"]"
infor+="\nCác Sản phẩm của danh Mục này là:\n"+s
return infor
}
fun ThemSanPham(sp:SanPham)
{
SanPhams.add(sp)
}
}

Như Tui đã nói ở bài 32, GSon không quan tâm cấu trúc và mối quan hệ giữa các lớp mà bạn viết như thế nào. Nó “cân” hết (đừng bị đệ quy là được, nếu ko nó bị stack over flow)

Giờ ta tiếp tụ tạo lớp JSonFileFactory, nó có cấu trúc như dưới đây (giống nhau trong mọi trường hợp nếu bạn dùng kiểu dữ liệu là Any)


import com.google.gson.Gson
import java.io.FileWriter
import java.io.FileReader
import com.google.gson.reflect.TypeToken

/**
* Created by cafe on 02/06/2017.
*/
class JSonFileFactory {
/**
* @author Trần Duy Thanh
* @param data: Dữ liệu là Danh sách sản phẩm muốn lưu
* @param path: Đường dẫn lưu trữ
* @return true nếu lưu thành công, false nếu lưu thất bại
*/
fun LuuFile(data:MutableList<DanhMuc>,path:String):Boolean
{
try {
val gs= Gson()
val file=FileWriter(path)
gs.toJson(data,file)
file.close()
return true
}
catch (ex:Exception)
{
ex.printStackTrace()
}
return false
}
/**
* @author Trần Duy Thanh
* @param path:đường dẫn muốn đọc dữ liệu
* @return Danh sách sản phẩm MutableList
*/
fun DocFile(path:String):MutableList<DanhMuc>
{
var data:MutableList<DanhMuc> = mutableListOf()
try
{
val gson = Gson()
var file=FileReader(path)
data = gson.fromJson<MutableList<DanhMuc>>(file,
object : TypeToken<MutableList<DanhMuc>>()
{
}.type
)
file.close()
}
catch (ex:Exception)
{
ex.printStackTrace()
}
return data
}
}

Cuối cùng ta tạo hàm main để kiểm tra:


fun main(args: Array<String>) {
var database:MutableList<DanhMuc> = mutableListOf<DanhMuc>()

var dmDienTu:DanhMuc=DanhMuc(1,"Mặt hàng điện tử")
database.add(dmDienTu)

var bongden:SanPham=SanPham(1,"Bóng đèn điện Quang",150.0)
dmDienTu.ThemSanPham(bongden)
var acquy:SanPham=SanPham(2,"Ắc quy Đồng Nai",250.0)
dmDienTu.ThemSanPham(acquy)
var maydien:SanPham=SanPham(3,"Máy phát điện ABC",90.0)
dmDienTu.ThemSanPham(maydien)

var dmTieuDung:DanhMuc=DanhMuc(2,"Mặt hàng tiêu dùng")
database.add(dmTieuDung)

var xabong:SanPham=SanPham(4,"Xà Bông Lifeboy",15.0)
dmTieuDung.ThemSanPham(xabong)
var nuocruachen:SanPham=SanPham(5,"Nước rửa chén Sunlight",12.0)
dmTieuDung.ThemSanPham(nuocruachen)

var dmHoaChat:DanhMuc=DanhMuc(3,"Mặt hàng Hóa Chất")
database.add(dmHoaChat)

var dietmuoi:SanPham=SanPham(6,"Thuốc Diệt Muỗi XYZ",80.0)
dmHoaChat.ThemSanPham(dietmuoi)
var dietchuot:SanPham=SanPham(7,"Thuốc Diệt Chuỗi ABC",70.0)
dmHoaChat.ThemSanPham(dietchuot)

for (dm in database)
println(dm)

var kqLuu= JSonFileFactory().LuuFile(database,"d:/dulieudanhmuc.json")
if(kqLuu)
{
println("Lưu Json file thành công")
}
else
{
println("Lưu Json file thất bại")
}
}

Khi chạy hàm main ở trên thì ta có kết quả sau:

Danh Mục:[1 Mặt hàng điện tử]
Các Sản phẩm của danh Mục này là:
1 Bóng đèn điện Quang 150.0
2 Ắc quy Đồng Nai 250.0
3 Máy phát điện ABC 90.0Danh Mục:[2 Mặt hàng tiêu dùng]
Các Sản phẩm của danh Mục này là:
4 Xà Bông Lifeboy 15.0
5 Nước rửa chén Sunlight 12.0

Danh Mục:[3 Mặt hàng Hóa Chất]
Các Sản phẩm của danh Mục này là:
6 Thuốc Diệt Muỗi XYZ 80.0
7 Thuốc Diệt Chuỗi ABC 70.0

Lưu Json file thành công

Bây giờ ta vào ổ D xem tập tin dulieudanhmuc.json có được lưu thành công hay chưa:

Rõ ràng kết quả đã lưu thành công, bạn quan sát thấy cấu trúc Json này có gì khác biệt? Đó là mỗi một đối tượng danh Mục nó một mảng SanPhams–>được GSon tự động tạo ra từ mối quan hệ của 2 Lớp DanhMuc + SanPham

Bây giờ ta sẽ gọi hàm đọc thông tin lên nhé:


fun main(args: Array<String>) {
var database:MutableList<DanhMuc> =
JSonFileFactory().DocFile("d:/dulieudanhmuc.json")
for (dm in database)
println(dm)
}

Khi chạy hàm main ở trên thì ta có kết quả sau:

Danh Mục:[1 Mặt hàng điện tử]
Các Sản phẩm của danh Mục này là:
1 Bóng đèn điện Quang 150.0
2 Ắc quy Đồng Nai 250.0
3 Máy phát điện ABC 90.0Danh Mục:[2 Mặt hàng tiêu dùng]
Các Sản phẩm của danh Mục này là:
4 Xà Bông Lifeboy 15.0
5 Nước rửa chén Sunlight 12.0

Danh Mục:[3 Mặt hàng Hóa Chất]
Các Sản phẩm của danh Mục này là:
6 Thuốc Diệt Muỗi XYZ 80.0
7 Thuốc Diệt Chuỗi ABC 70.0

Có vẻ tới đây các bạn thấy rằng JSon sẽ dễ lập trình hơn Text File, Serialize File, và XML File đúng không? Hiện nay cấu trúc JSon được sử dụng rất nhiều, ngày càng phổ biến và các lập trình viên rất thích điều này.

Như vậy ta đã Ví dụ xong trường hợp phức  tạp của JSon File đó là có mối quan hệ giữa các lớp, các bạn tự áp dụng vào các dự án cụ thể nhé. Bài sau Tui sẽ trình bày thêm cách lấy dữ liệu Json từ Internet trong Kotlin. Cụ thể là lấy Tỉ Giá hối đoái của Ngân Hàng Đông Á, Json có cấu trúc phức tạp, các bạn chú ý theo dõi nhé

Các bạn có thể tải source code bài này ở đây: http://www.mediafire.com/file/hk795a31148wsb0/HocJSon_DanhMucSanPham.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/)

Bài 32-Xử lý JSon trong Kotlin – Bài 1


Các bạn đã nắm được 3 kiểu tương tác File: Text File, Serialize File, XML file. Bây giờ Tui hướng dẫn loại định dạng file cuối cùng rất nổi tiếng hiện nay đó là định dạng Json.

Khái niệm về JSon Tui đã trình bày ở bài 51 của Android, các bạn có thể vào bài này để đọc thêm.

Kotlin cũng có sẵn các lớp để tương tác Json, hoặc có nhiều thư viện ngoài rất nổi tiếng như GSon, Klaxon… giúp chúng ta dễ dàng chuyển Object Model thành Json và từ Json thành Object Model vô cùng lợi hại.

Trong bài này Tui sẽ hướng dẫn các bạn cách dùng GSon trong Kotlin để chuyển đổi qua loại giữa Object Model và Json.

Tính tới thời điểm Tui viết bài học này thì GSon có phiên bản mới nhất là 2.8.1 (update ngày 31/05/2017)

Bạn cần tải thư viện này về rồi reference nó vào Project trong IntelliJ IDEA của bạn.

Để tải GSon 2.8.1 bạn vào link: https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.1/

Tải tập tin gson-2.8.1.jar (dụng lượng khoảng 228kb) từ  link ở trên về máy tính.

Tui nói sơ qua cách thức hoạt động của GSon:

Để chuyển đổi Kotlin Model tới JSon ta làm như sau:

    val gson = Gson()
    val obj = KotlinModel()//lớp nào đó trong Kotlin

// 1. Kotlin object to JSON, and save into a file
    val file=FileWriter("D:\\file.json")
    gson.toJson(obj, file)
    file.close()
// 2. Kotlin object to JSON, and assign to a String
    val jsonInString = gson.toJson(obj)

Để chuyển đổi JSon về Kotlin Model ta làm như sau:

val gson = Gson()

// 1. JSON to Kotlin model, read it from a file.
    val data = gson.fromJson(FileReader("D:\\file.json"), SanPham::class.java)

// 2. JSON to Kotlin Model, read it from a Json String.
    val jsonInString = "{'name' : 'cocacola'}"
    val data= gson.fromJson(jsonInString, SanPham::class.java)

// JSON to JsonElement, convert to String later.
    val json = gson.fromJson(FileReader("D:\\file.json"), JsonElement::class.java)
    val result = gson.toJson(json)

Nếu dữ liệu Json là dạng JsonArray  thì để đưa về Kotlin  Model ta phải làm như sau:

val gson = Gson()
val json = "[{\"name\":\"cocacola\"}, {\"name\":\"pepsi\"}]"
val data:MutableList = gson.fromJson(json, 
        object : TypeToken() 
        {}.type)

Bây giờ Tui sẽ hướng dẫn chi tiết từng bước cụ thể để các bạn có thể dễ dàng hiểu và vận dụng thư viện GSon.

Tạo một Project tên là HocJSonFile, từ Project này ta tạo 1 thư mục(directory) tên là libs để chép thư viện gson-2.8.1.jar vào libs:

Bấm chuột phải vào Project/ chọn New/ chọn Directory:

Đặt tên directory là libs rồi bấm Ok, lúc này thư mục libs sẽ được tạo ra trong Project. Ta chép gson-2.8.1.jar vào thư mục này như hình dưới đây:

Tiếp theo ta cần đưa gson-2.8.1.jar thành thư viện sử dụng trong Project, cách làm như sau:

Bấm chuột phải vào gson-2.8.1.jar rồi chọn add as Library như hình ở trên, màn hình cấu hình sẽ xuất hiện:

Đặt tên(để mặc định) rồi bấm OK, lúc này bạn quan sát có sự thay đổi trong cách hiển thị, thấy được tập các lớp nằm trong thư viện này:

Bây giờ ta tiến hành tạo lớp Sản phẩm giống như các kỹ thuật xử lý text file, serialize file, xml file mà bạn đã được học trước đó:


import java.io.Serializable
/**
* Created by cafe on 02/06/2017.
*/
class SanPham:Serializable {
var ma:Int=0
var ten:String=""
var donGia:Double=0.0
constructor()
constructor(ma: Int, ten: String, donGia: Double) {
this.ma = ma
this.ten = ten
this.donGia = donGia
}
override fun toString(): String {
return "$ma\t$ten\t$donGia"
}
}

Tiếp tục tạo lớp JSonFileFactory để Lưu và đọc Json bằng GSon:


import com.google.gson.Gson
import java.io.FileWriter
import java.io.FileReader
import com.google.gson.reflect.TypeToken

/**
* Created by cafe on 02/06/2017.
*/
class JSonFileFactory {
/**
* @author Trần Duy Thanh
* @param data: Dữ liệu là Danh sách sản phẩm muốn lưu
* @param path: Đường dẫn lưu trữ
* @return true nếu lưu thành công, false nếu lưu thất bại
*/
fun LuuFile(data:MutableList<SanPham>,path:String):Boolean
{
try {
val gs= Gson()
val file=FileWriter(path)
gs.toJson(data,file)
file.close()
return true
}
catch (ex:Exception)
{
ex.printStackTrace()
}
return false
}
/**
* @author Trần Duy Thanh
* @param path:đường dẫn muốn đọc dữ liệu
* @return Danh sách sản phẩm MutableList
*/
fun DocFile(path:String):MutableList<SanPham>
{
var data:MutableList<SanPham> = mutableListOf()
try
{
val gson = Gson()
var file=FileReader(path)
data = gson.fromJson<MutableList<SanPham>>(file,
object : TypeToken<MutableList<SanPham>>()
{
}.type
)
file.close()
}
catch (ex:Exception)
{
ex.printStackTrace()
}
return data
}
}

Bạn thấy đấy, Gson giúp chúng ta đơn giản hóa mọi việc lưu và đọc dữ liệu. Đây là một trong những thư viện nổi tiếng, được sử dụng rất nhiều trong các dự án, và định dạng dữ liệu JSon ngày càng phổ biến, có thể hơn cả XML vốn đã nổi đình nổi đám trước đó.

Cuối cùng ta tạo hàm main để kiểm tra:


fun main(args: Array<String>) {

var data:MutableList<SanPham> = mutableListOf()
var sp1=SanPham(1,"Coca cola",15.5)
data.add(sp1)
var sp2=SanPham(2,"Sting",25.0)
data.add(sp2)
var sp3=SanPham(3,"Redbull",17.0)
data.add(sp3)
var kqLuu= JSonFileFactory().LuuFile(data,"d:/dulieusanpham.json")
if(kqLuu)
{
println("Lưu Json file thành công")
}
else
{
println("Lưu Json file thất bại")
}
}

Khi chạy hàm main ở trên thì ta có kết quả sau:

Lưu Json file thành công

Bây giờ ta vào ổ D xem tập tin dulieusanpham.json có được lưu thành công hay chưa:

Rõ ràng kết quả đã lưu thành công, bây giờ ta sẽ gọi hàm đọc thông tin lên nhé:


fun main(args: Array<String>) {
var data:MutableList<SanPham> = JSonFileFactory().DocFile("d:/dulieusanpham.json")
for (sp in data)
println(sp)
}

Khi chạy hàm main ở trên thì ta có kết quả sau:

1 Coca cola 15.5
2 Sting 25.0
3 Redbull 17.0

Như vậy ta đã lưu và đọc JSon File thành công, các bạn tự áp dụng vào các dự án cụ thể nhé, cấu trúc JSon File trong trường hợp này nó sẽ tự động build dựa vào cấu trúc Class và mối quan hệ giữa các Class mà bạn tạo ra.

Bài sau Tui sẽ trình bày thêm cách lấy dữ liệu Json từ Internet trong Kotlin, các Json có cáu trúc phức tạp, các bạn chú ý theo dõi nhé

Các bạn có thể tải source code bài này ở đây: http://www.mediafire.com/file/7jgvvzyschy77gg/HocJSonFile.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/)

Bài 31-Xử lý XML File trong Kotlin


Chúng ta đã biết xử lý Text File, Serialize File, trong bài này Tui sẽ hướng dẫn các bạn cách lưu và đọc  dữ liệu với XML File.

Tui vẫn sử dụng các thư viện trong JVM để xử lý cho Kotlin. Cũng với ví dụ như các bài xử lý file trước đó, ta có lớp Sản phẩm với thông tin như sau:


import java.io.Serializable

/**
* Created by cafe on 02/06/2017.
*/
class SanPham {
var ma:Int=0
var ten:String=""
var donGia:Double=0.0
constructor()
constructor(ma: Int, ten: String, donGia: Double) {
this.ma = ma
this.ten = ten
this.donGia = donGia
}
override fun toString(): String {
return "$ma\t$ten\t$donGia"
}
}

Cấu trúc file XML Tui muốn các bạn phải lưu trữ thành:


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SanPhams>
<SanPham>
  <Ma>1</Ma>
  <Ten>Coca cola</Ten>
  <Gia>15.5</Gia>
</SanPham>
<SanPham>
 <Ma>2</Ma>
 <Ten>Sting</Ten>
 <Gia>25.0</Gia>
</SanPham>
<SanPham>
 <Ma>3</Ma>
 <Ten>Redbull</Ten>
 <Gia>17.0</Gia>
</SanPham>
</SanPhams>

Để lưu và đọc được XML File thì ta phải sử dụng các thư viện sau:

import java.io.File
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.stream.StreamResult
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.TransformerFactory
import org.w3c.dom.Element

Tui có tạo 1 lớp XMLFileFactory có 2 phương thức để ghi file XML và đọc file XML. Các bạn muốn hiểu rõ thêm về XML thì nên học thêm các kiến thức về XML. Trong bài học này Tui cung cấp các  lệnh để các bạn có thể áp dụng vào việc ghi và đọc File (Tui không giải thích sâu, vì các bạn là dân lập trình nên chắc chắn đọc sẽ suy luận được. Nếu bạn khó hiểu thì cứ nhớ trong đầu như sau: Hàm LuuFile là hàm đưa dữ liệu danh sách Sản phẩm thành file XML, hàm DocFile mô hình hóa ngược lại từ tập dữ liệu XML thành hướng đối tượng trong Kotlin -là danh Sách Sản Phẩm).


import java.io.File
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.stream.StreamResult
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.TransformerFactory
import org.w3c.dom.Element

/**
* Created by cafe on 02/06/2017.
*/
class XMLFileFactory {
/**
* @author Trần Duy Thanh
* @param data: Dữ liệu là Danh sách sản phẩm muốn lưu
* @param path: Đường dẫn lưu trữ
* @return true nếu lưu thành công, false nếu lưu thất bại
*/
fun LuuFile(data:MutableList<SanPham>,path:String):Boolean
{
try
{
val docFactory = DocumentBuilderFactory.newInstance()
val docBuilder = docFactory.newDocumentBuilder()
// root elements
val doc = docBuilder.newDocument()
val rootElement = doc.createElement("SanPhams")
doc.appendChild(rootElement)
for(sp in data)
{
val sanPhamElement = doc.createElement("SanPham")
val maElement=doc.createElement("Ma")
maElement.textContent=sp.ma.toString()
sanPhamElement.appendChild(maElement)
val tenElement=doc.createElement("Ten")
tenElement.textContent=sp.ten
sanPhamElement.appendChild(tenElement)
val giaElement=doc.createElement("Gia")
giaElement.textContent=sp.donGia.toString()
sanPhamElement.appendChild(giaElement)
rootElement.appendChild(sanPhamElement);
}
// write the content into xml file
val transformerFactory = TransformerFactory.newInstance()
val transformer = transformerFactory.newTransformer()
val source = DOMSource(doc)

val result = StreamResult(File(path).absolutePath)

// Output to console for testing
// StreamResult result = new StreamResult(System.out);
transformer.transform(source, result)
return true
}
catch (ex:Exception)
{
ex.printStackTrace()
}
return false
}

/**
* @author Trần Duy Thanh
* @param path:đường dẫn muốn đọc dữ liệu
* @return Danh sách sản phẩm MutableList
*/
fun DocFile(path:String):MutableList<SanPham>
{
var data:MutableList<SanPham> = mutableListOf()
try {
//Get the DOM Builder Factory
val factory = DocumentBuilderFactory.newInstance()

//Get the DOM Builder
val builder = factory.newDocumentBuilder()

//Load and Parse the XML document
//document contains the complete XML as a Tree.
val xmlfile = File(path)

val document = builder.parse(xmlfile)

//Iterating through the nodes and extracting the data.
val nodeList = document.documentElement.childNodes

for (i in 0..nodeList.length - 1) {

//We have encountered an <SanPham> tag.
val node = nodeList.item(i)
if (node is Element) {
val sp = SanPham()
val childNodes = node.getChildNodes()
for (j in 0..childNodes.getLength() - 1) {
val cNode = childNodes.item(j)

//Identifying the child tag of employee encountered.
if (cNode is Element) {
val content = cNode.getLastChild().getTextContent().trim()
when (cNode.getNodeName()) {
"Ma" -> sp.ma= content.toInt()
"Ten" -> sp.ten= content
"Gia" -> sp.donGia= content.toDouble()
}
}
}
data.add(sp)
}
}
}
catch (ex:Exception)
{
ex.printStackTrace()
}
return data
}
}

Ta tạo một hàm main để thử nghiệm việc lưu XML FILE:


fun main(args: Array<String>) {
var data:MutableList<SanPham> = mutableListOf()
var sp1=SanPham(1,"Coca cola",15.5)
data.add(sp1)
var sp2=SanPham(2,"Sting",25.0)
data.add(sp2)
var sp3=SanPham(3,"Redbull",17.0)
data.add(sp3)
var kqLuu= XMLFileFactory().LuuFile(data,"d:/dulieusanpham.xml")
if(kqLuu)
{
println("Lưu text file thành công")
}
else
{
println("Lưu text file thất bại")
}
}

Khi chạy hàm main ở trên thì ta có kết quả sau:

Lưu text file thành công

Bây giờ ta vào ổ D xem tập tin dulieusanpham.xml có được lưu thành công hay chưa:

Rõ ràng kết quả đã lưu thành công, bây giờ ta sẽ gọi hàm đọc thông tin lên nhé:


fun main(args: Array<String>) {
var data:MutableList<SanPham> = XMLFileFactory().DocFile("d:/dulieusanpham.xml")
for (sp in data)
println(sp)
}

Khi chạy hàm main ở trên thì ta có kết quả sau:

1 Coca cola 15.5
2 Sting 25.0
3 Redbull 17.0

Như vậy ta đã lưu và đọc XML File thành công, các bạn tự áp dụng vào các dự án cụ thể nhé, cấu trúc XML File như thế nào là do bạn quyết định

Các bài sau Tui sẽ trình bày về Xử lý JSON File trong Kotlin rất quan trọng trong quá trình xử lý lưu trữ dữ liệu

Các bạn có thể tải source code bài này ở đây: http://www.mediafire.com/file/lh1024w1b722but/HocXMLFile.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/)

Bài 30-Xử lý Serialize File trong Kotlin


Bạn đã được học xử lý Text File ở bài 29, Trong bài này Tui tiếp tục hướng dẫn chuỗi bài học xử lý file, đó là Serialize File trong Kotlin

Cũng giống như Text File, Kotlin cũng dùng các thư viện JVM để xử lý Serialize nên nó cũng rất giống với Java.

Serialize File cho phép ta “chụp ảnh” đối tượng xuống ổ cứng và phục hồi hình ảnh từ ổ cứng lên bộ nhớ. Để lưu được dạng Serialize thì các lớp có lưu trữ xuống ổ cứng phải kế thừa interface Serialize.

Các gói thư viện dùng để chụp ảnh và phục hồi ảnh trong trường hợp này gồm:

import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.ObjectInputStream
import java.io.ObjectOutputStream

Ta tạo một Project mới, cho các lớp tương tự như bài 29 để các bạn dễ so sánh:

Lớp Sản phẩm sẽ implements interface Serialize như dưới đây:


import java.io.Serializable
/**
* Created by cafe on 02/06/2017.
*/
class SanPham:Serializable {
var ma:Int=0
var ten:String=""
var donGia:Double=0.0
constructor()
constructor(ma: Int, ten: String, donGia: Double) {
this.ma = ma
this.ten = ten
this.donGia = donGia
}
override fun toString(): String {
return "$ma\t$ten\t$donGia"
}
}

Tiếp tục tạo lớp SerializableFileFactory để cung cấp 2 hàm Lưu và đọc tập tin dạng Serialize, kỹ thuật viết như sau:


import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.ObjectInputStream
import java.io.ObjectOutputStream

/**
* Created by cafe on 02/06/2017.
*/
class SerializableFileFactory {
/**
* @author Trần Duy Thanh
* @param data: Dữ liệu là Danh sách sản phẩm muốn lưu
* @param path: Đường dẫn lưu trữ
* @return true nếu lưu thành công, false nếu lưu thất bại
*/
fun LuuFile(data:MutableList<SanPham>,path:String):Boolean
{
try {
var fos=FileOutputStream(path);
var oos=ObjectOutputStream(fos);
oos.writeObject(data);
oos.close();
fos.close();
return true
}
catch (ex:Exception)
{
ex.printStackTrace()
}
return false
}
/**
* @author Trần Duy Thanh
* @param path:đường dẫn muốn đọc dữ liệu
* @return Danh sách sản phẩm MutableList
*/
fun DocFile(path:String):MutableList<SanPham>
{
var data:MutableList<SanPham> = mutableListOf()
try
{
var fis=FileInputStream(path);
var ois=ObjectInputStream(fis);
var obj=ois.readObject();
data= obj as MutableList<SanPham>;
ois.close();
fis.close();
}
catch (ex:Exception)
{
ex.printStackTrace()
}
return data
}
}

Ta thấy cách lưu và đọc tập tin dạng Serialize đơn giản hơn rất nhiều so với Text File, và các bạn chú ý là nó không quan tâm cấu trúc mối quan hệ nhằng nhịt giữa các lớp như thế nào. Nó chụp 1 cái BỤP là lưu hết toàn bộ xuống ổ cứng luôn.

Bây giờ tạo hàn main để Test lưu chụp ảnh đối tượng:


/**
* Created by cafe on 02/06/2017.
*/
fun main(args: Array<String>) {
var data:MutableList<SanPham> = mutableListOf()
var sp1=SanPham(1,"Coca cola",15.5)
data.add(sp1)
var sp2=SanPham(2,"Sting",25.0)
data.add(sp2)
var sp3=SanPham(3,"Redbull",17.0)
data.add(sp3)
var kqLuu=SerializableFileFactory().LuuFile(data,"d:/dulieusanpham.dat")
if(kqLuu)
{
println("Lưu text file thành công")
}
else
{
println("Lưu text file thất bại")
}
}

Ở trên Tui lưu tập tin với tập dulieusanpham.dat (đuôi gì cũng được):

Khi chạy hàm main ở trên thì ta có kết quả sau:

Lưu text file thành công

Bây giờ ta vào ổ D xem tập tin dulieusanpham.dat có được lưu thành công hay chưa:

Mở bằng Notepad, bạn thấy nó ra giun dế loằng ngoằng, không giống như Text File

Rõ ràng kết quả đã lưu thành công, bây giờ ta sẽ gọi hàm đọc thông tin lên nhé:


fun main(args: Array<String>) {
var data:MutableList<SanPham> = SerializableFileFactory().DocFile("d:/dulieusanpham.dat")
for (sp in data)
println(sp)
}

Khi chạy hàm main ở trên thì ta có kết quả sau:

1 Coca cola 15.5
2 Sting 25.0
3 Redbull 17.0

Như vậy ta đã lưu và đọc Serialize File thành công, các bạn tự áp dụng vào các dự án cụ thể nhé, cấu trúc Serialize File là dạng nhị phân nên ta đọc không hiểu, chỉ phần mềm của ta đọc mới hiểu.

Các bài sau Tui sẽ trình bày về Xử lý XML File trong Kotlin rất quan trọng trong quá trình xử lý lưu trữ dữ liệu

Các bạn có thể tải source code bài này ở đây: http://www.mediafire.com/file/v66y0alecg7q515/HocSerializeFile.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/)

Bài 29-Xử lý Text File trong Kotlin


Trong tất cả các ngôn ngữ lập trình thì xử lý file rất quan trọng, hầu như ta phải gặp trong các dự án. Tui sẽ trình bày chuỗi 4 bài xử lý file: Text File, Serialize File, XML File, JSon File để các bạn có nhiều lựa chọn trong quá trình xử lý tập tin.

Tại sao phải lưu trữ dữ liệu? Như chúng ta đã biết trong kiến trúc máy tính, một chương trình muốn hoạt động thì mọi tài nguyên phải được nạp lên bộ nhớ, cụ thể là trên thanh RAM. Mà nguyên lý của RAM là bộ nhớ tạm, khi tắt phần mềm, tắt máy… thì dữ liệu trong bộ nhớ sẽ không còn nữa. Giả sử chúng ta đang nhập liệu 100 Sản phẩm thì tự nhiên cúp điện, nếu không có cơ chế lưu dữ liệu từ bộ nhớ RAM xuống ổ cứng thì sẽ mất toàn bộ dữ liệu.

Text File là cách lưu trữ dữ liệu dạng thô, ta có thể mở tập tin lên xem cấu trúc, nội dung và chỉnh sửa được.

Kotlin dùng các thư viện JVM để tương tác File nên nó giống y xì như Java, từ Kotlin ta sẽ triệu gọi các thư viện Java. Do đó để bổ trợ tốt cho Kotlin thì các bạn nên đăng ký tham gia học Java trước.

Để lưu và đọc Text File, tương tự như Java thì Kotlin sẽ phải import các thư viện sau:

import java.io.BufferedWriter
import java.io.OutputStreamWriter
import java.io.FileOutputStream
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.FileInputStream

Giả sử ta có một cấu trúc dữ liệu (class) Sản phẩm như sau:


/**
* Created by cafe on 02/06/2017.
*/
class SanPham {
var ma:Int=0
var ten:String=""
var donGia:Double=0.0
constructor()
constructor(ma: Int, ten: String, donGia: Double) {
this.ma = ma
this.ten = ten
this.donGia = donGia
}
override fun toString(): String {
return "$ma\t$ten\t$donGia"
}
}

Bây giờ ta sẽ viết Lớp để lưu danh sách Sản phẩm như sau (Lớp TextFileFactory):


import java.io.BufferedWriter
import java.io.OutputStreamWriter
import java.io.FileOutputStream
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.FileInputStream

/**
* Created by cafe on 02/06/2017.
*/
class TextFileFactory {
/**
* @author Trần Duy Thanh
* @param data: Dữ liệu là Danh sách sản phẩm muốn lưu
* @param path: Đường dẫn lưu trữ
* @return true nếu lưu thành công, false nếu lưu thất bại
*/
fun LuuFile(data:MutableList<SanPham>,path:String):Boolean
{
try {
val fos = FileOutputStream(path)
val osw = OutputStreamWriter(fos, "UTF-8")
val bw = BufferedWriter(osw)
for (sp in data) {
bw.write(sp.toString());
bw.newLine();
}
bw.close();
osw.close();
fos.close();
return true
}
catch (ex:Exception)
{
ex.printStackTrace()
}
return false
}

/**
* @author Trần Duy Thanh
* @param path:đường dẫn muốn đọc dữ liệu
* @return Danh sách sản phẩm MutableList
*/
fun DocFile(path:String):MutableList<SanPham>
{
var data:MutableList<SanPham> = mutableListOf()
try {
val fis = FileInputStream(path)
val isr = InputStreamReader(fis, "UTF-8")
val br = BufferedReader(isr)

var line = br.readLine()
while (line != null) {
var arr = line.split("\t")
if (arr.size == 3) {
var sp: SanPham = SanPham()
sp.ma = arr[0].toInt()
sp.ten = arr[1]
sp.donGia = arr[2].toDouble()
data.add(sp)
}
line = br.readLine()
}
br.close()
isr.close()
fis.close()
}
catch (ex:Exception)
{
ex.printStackTrace()
}
return data
}
}

Bây giờ ta tạo hàm main trong tập tin app_test_textfile.kt để test lưu và đọc danh sách Sản phẩm dạng Text File:


/**
* Created by cafe on 02/06/2017.
*/
fun main(args: Array<String>) {
var data:MutableList<SanPham> = mutableListOf()
var sp1=SanPham(1,"Coca cola",15.5)
data.add(sp1)
var sp2=SanPham(2,"Sting",25.0)
data.add(sp2)
var sp3=SanPham(3,"Redbull",17.0)
data.add(sp3)
var kqLuu=TextFileFactory().LuuFile(data,"d:/dulieusanpham.txt")
if(kqLuu)
{
println("Lưu text file thành công")
}
else
{
println("Lưu text file thất bại")
}
}

Khi chạy hàm main ở trên thì ta có kết quả sau:

Lưu text file thành công

Bây giờ ta vào ổ D xem tập tin dulieusanpham.txt có được lưu thành công hay chưa:

Rõ ràng kết quả đã lưu thành công, bây giờ ta sẽ gọi hàm đọc thông tin lên nhé:


fun main(args: Array<String>) {
var data:MutableList<SanPham> = TextFileFactory().DocFile("d:/dulieusanpham.txt")
for (sp in data)
println(sp)
}

Khi chạy hàm main ở trên thì ta có kết quả sau:

1 Coca cola 15.5
2 Sting 25.0
3 Redbull 17.0

Như vậy ta đã lưu và đọc Text File thành công, các bạn tự áp dụng vào các dự án cụ thể nhé, Lưu cấu trúc Text File như thế nào là do quyết định của bạn, bài trên Tui lưu mỗi đối tượng là 1 dòng, và các thuộc tính ngăn cách bởi 1 dấu tab.

Các bài sau Tui sẽ trình bày về Xử lý Serialize File trong Kotlin rất quan trọng trong quá trình xử lý lưu trữ dữ liệu

Các bạn có thể tải source code bài này ở đây: http://www.mediafire.com/file/tnyg7czel2zx7oy/HocTextFile.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/)

Bài 28-Extensions Method trong Kotlin-OOP phần 7


Kotlin hỗ trợ Extensions Method rất tuyệt với, giống như LINQ trong C#(bạn nào quan tâm thì đăng ký học khóa học LinQ C# ở đây). Extensions Method cho phép ta chèn thêm phương thức vào các Lớp có sẵn mà không cần sửa mã nguồn, không cần biết mã nguồn, giống như là cài đặt virus vào một chương trình nào đó.Cú pháp:

fun [Kiểu_Dữ_Liệu].Tên_Hàm([Các đối số]):[Kiểu_Trả_Về]

{

this ở trong này là đối tượng thuộc [Kiểu_Dữ_Liệu]

}

Khi khai báo như trên, thì bất kỳ [Kiểu_Dữ_Liệu] nào cũng có một hàm mới là Tên_Hàm

Ví dụ 1: Hãy cài đặt hàm Cong (Cộng) vào kiểu Int


/**
* Created by cafe on 02/06/2017.
*/
fun Int.Cong(a:Int):Int
{
return this+a
}
fun main(args: Array<String>) {
var t=5.Cong(9)
println("t=$t")
var x1=9
var x2=10
var x3=x1.Cong(x2)
println("x3=$x3")
}

Bạn nhìn vào dòng 4 Tui khai báo Int.Cong ==> là cài đặt hàm Cong vào kiểu Int

dòng lệnh số 6 có từ khoa this, this ở đây chính là đối tượng hiện tại của kiểu Int.

Bạn tiếp tục quan sát dòng số 9, thấy số 5.Cong(9) . Vì 5 là số Nguyên kiểu Int mà kiểu Int ta vừa cài đặt hàm Cong nên hiển nhiên 5 sẽ có phương thức Cong. Bạn để ý là Ta không hề biết Kotlin tjao ra Int như thế nào nhưng ta vẫn có thể thêm phương thức Cong vào Int mà không cần biết mã nguồn cũ cũng không cần sửa mã nguồn cũ.

Khi chạy hàm main ở trên thì ta có kết quả sau:

t=14
x3=19

Ví dụ 2: Cài đặt hàm kiểm tra 1 số có phải là số Nguyên Tố hay không vào kiểu Int có sẵn của Kotlin


/**
* Created by cafe on 02/06/2017.
*/
fun Int.Cong(a:Int):Int
{
return this+a
}
fun Int.KiemTraNguyenTo():Boolean
{
var dem=0
for(i in 1..this)
{
if(this%i==0)
dem++
}
return dem==2
}
fun main(args: Array<String>) {
var t=5.Cong(9)
println("t=$t")
var x1=9
var x2=10
var x3=x1.Cong(x2)
println("x3=$x3")

var a=7
if(a.KiemTraNguyenTo()==true)
{
println("$a là số nguyên tố")
}
else
{
println("$a Ko là số nguyên tố")
}
var b=9
if(b.KiemTraNguyenTo()==true)
{
println("$b là số nguyên tố")
}
else
{
println("$b Ko là số nguyên tố")
}
}

Dòng số 8 ở trên là cài đặt hàm KiemTraNguyenTo() vào kiểu Int

Dòng 27 và 36 là sử dụng hàm KiemTraNguyenTo() có sẵn trong Int (do ta cài vào).

Khi chạy hàm main kết quả như sau:

t=14
x3=19
7 là số nguyên tố
9 Ko là số nguyên tố

Khi chạy kết quả

Ví dụ 3:Cài đặt hàm Tính Tuổi cho Lớp Sinh Viên được viết sẵn của ai đó, Lớp Sinh Viên này có cấu trúc như sau:


import java.util.*

/**
* Created by cafe on 02/06/2017.
*/
class SinhVien {
private var ma:Int=0
private var ten:String?=null
private var namSinh:Date?=null
public var Ma:Int
get() {return ma}
set(value) {ma=value}
public var Ten:String?
get()= ten
set(value) {ten=value}
public var NamSinh:Date?
get() = namSinh
set(value) {namSinh=value}
constructor(ma: Int, ten: String?, namSinh: Date?) {
this.ma = ma
this.ten = ten
this.namSinh = namSinh
}
}

Vậy làm sao để cài đặt hàm tính tuổi cho lớp Sinh Viên này? (không được đổi mã nguồn cũ). Rất dễ dàng ta làm như sau:


import java.util.*

/**
* Created by cafe on 02/06/2017.
*/
fun SinhVien.Tuoi():Int
{
var cal=Calendar.getInstance()
var yearHienTai=cal.get(Calendar.YEAR)
cal.time=this.NamSinh
var yearNamSinh=cal.get(Calendar.YEAR)
return yearHienTai-yearNamSinh+1
}
fun main(args: Array<String>) {
var ns=Calendar.getInstance()
ns.set(Calendar.YEAR,1998)
ns.set(Calendar.MONTH,2)
ns.set(Calendar.DAY_OF_MONTH,15)
var teo=SinhVien(1,"Nguyễn Văn Tèo",ns.time)
var tuoiCuaTeo=teo.Tuoi()
println("Tuổi của Tèo="+tuoiCuaTeo)
}

Dòng số 6 ở trên ta cài đặt hàm Tuoi() vào Lớp Sinh Viên. Dựa vào 3 ví dụ ở trên mà bạn có thể áp dụng vào các dự án bất kỳ.

Khi chạy hàm main ở trên thì kết quả là gì?

Tuổi của Tèo=20

Như vậy tới đây Tui đã trình bày xong Extensions Method trong Kotlin. 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ề Xử lý File trong Kotlin rất quan trọng trong quá trình xử lý lưu trữ dữ liệu

Các bạn có thể tải source code bài này ở đây: http://www.mediafire.com/file/3wd89egcx10qim7/HocExtension.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/)

Bài 27-Alias và cơ chế gom rác tự động trong Kotlin-OOP phần 6


Như vậy hầu hết các bạn đã học xong hướng đối tượng cài đặt bằng Kotlin, trong bài này Tui sẽ nói thêm về Alias và cơ chế gom rác tự động trong Kotlin.

Alias là khả năng mà tại 1 ô nhớ có nhiều đối tượng cùng trỏ tới (>=2 đối tượng).

Cơ chế gom rác tự động còn gọi là garbage collection, nó tự động thu hồi bộ nhớ khi ô nhớ đó không còn đối tượng nào quan lý.

Hai khái niệm này vô cùng quan trọng, các bạn cần phải đảm bảo hiểu rõ nguộn ngành về nó để có thể kiếm soát vấn đề quản lý bộ nhớ khi thực thi các dự án.

Bây giờ Tui sẽ trình bày chi tiết quá trình tạo Alias và garbage collection trong Kotlin (các ngôn ngữ khác tương tự)

Vì Kotlin chạy trong nền JVM nên cơ chế hoạt động sẽ giống với Java.

Để cho có cảm giác về Alias và cơ chế gom rác tự động, ta tạo một lớp phân số như sau:


/**
* Created by cafe on 02/06/2017.
*/
class PhanSo {
var tu:Int=1
var mau:Int=1

constructor(tu: Int, mau: Int) {
this.tu = tu
this.mau = mau
}
}

Giả sử chúng ta có 2 đối tượng psA, psB như dưới đây:

psA=PhanSo(1,5)

psB=PhanSo(3,7)

Lúc này trên thanh RAM sẽ có 2 ô nhớ cấp phát cho 2 đối tượng phân số được quản lý bởi 2 biến đối tượng psA và psB (Chú ý là phải tưởng tượng nha các thím, chứ mình làm sao biết ô nhớ nào trên thanh RAM được cấp phát):

Hình trên cho thấy 2 đối tượng psA và psB quản lý 2 ô nhớ độc lập. Tức là psA thao tác trên vùng nhớ A sẽ không ảnh hưởng gì tới psB và ngược lại.

Bây giờ Giả sử ta thực hiện lệnh:

psA=psB

Thì lệnh trên: Ngôn ngữ nói “Phân số A bằng Phân số B”, nhưng hệ thống máy tính sẽ làm việc theo cơ chế “Phân số A trỏ tới vùng nhớ mà phân số B đang quản lý”. Hay nói cách khác “Vùng nhớ B” bây giờ có 2 biến đối tượng cùng trỏ tới(cùng quản lý):Như vậy đã xuất hiện Alias ở “vùng nhớ B”. Lúc này sẽ xảy ra 2 hiện tượng như sau:

  • Tại “vùng nhớ B”, nếu psA thay đổi thông tin sẽ làm cho psB thay đổi thông tin (vì cả 2 đối tượng này cùng quản lý một vùng nhớ)
  • “Vùng nhớ A” không còn đối tượng nào tham chiếu tới, lúc này hệ thống sẽ tự động thu hồi bộ nhớ (hủy vùng nhớ A đã cấp trước đó), cơ chế này gọi là cơ chế gom rác tự động

Hình sau minh họa GC (garbage collection):

Tức là trong hàm main ta có như sau:


/**
* Created by cafe on 02/06/2017.
*/
fun main(args: Array<String>) {
var psA=PhanSo(1,5)
var psB=PhanSo(3,7)
psA=psB
println("Tử số của A="+psA.tu)
}

Nếu bạn đã hiểu những gì Tui giải thích ở trên thì: Dòng lệnh số 7 phát sinh ra 2 hiện tượng. Đầu tiên là Alias (psA và psB cùng trỏ tới 1 ô nhớ), Thứ hai là Cơ chế gom rác tự động sẽ tự động thu hồi bộ nhớ cấp cho psA ở dòng 5 (vì lúc này psA đã trỏ qua vùng nhớ của psB).

Khi chạy hàm main ở trên thì kết quả là gì?

Tử số của A=3

Vấn đề là bạn có hiểu vì sao Tử số của A bằng 3 hay không? rõ ràng bên trên Khai báo psA=PhanSo(1,5) thì Tử số của psA là 1 chứ sao là 3 được? hi hi  hi rõ ràng bạn phải hiểu dòng lệnh số 7 đã làm thay đổi điều đó rồi, lúc này psA đã trỏ qua vùng nhớ mà psB đang trỏ. Mà vùng nhớ psB đang trỏ thì tử số bằng mấy? nó bằng 3 chứ gì nữa ==> tử số của psA phải là 3 chứ không phải 1 vì psA đã trỏ qua vùng nhớ của psB rồi…. do you understand?

Tiếp tục nếu giả sử Tui sửa tiếp coding như sau:


/**
* Created by cafe on 02/06/2017.
*/
fun main(args: Array<String>) {
var psA=PhanSo(1,5)
var psB=PhanSo(3,7)
psA=psB
println("Tử số của A="+psA.tu)
psA.tu=113
println("Tử số của B="+psB.tu)
}

Khi chạy hàm main ở trên thì kết quả là gì?

Tử số của A=3
Tử số của B=113

Bạn có hiểu vì sao Tử số của B=113 không? thật phi lý đúng không? rõ ràng dòng lệnh 9 mình chỉ đổi psA.tu=113, đâu có đổi tử số của phân số B đâu, tại sao tử số của B bị đổi theo A? Nó phải là 113 mới đúng, rất có lý không hề phi lý chút nào. Vì như trên Tui giải thích là vùng nhớ B có psA và psB cùng trỏ tới, do đó psA đổi cùng làm psB đổi và ngược lại, do đó khi psA.tu=113 tức là psB.tu cũng bằng 113. Các bạn cứ tưởng tượng thế này: Nếu Tui và các bạn cùng sử dụng chung 1 thẻ ATM, một ngày đẹp trời Tui buồn buồn Tui lấy hết sạch tiền trong ATM đó đi Nhậu –> bạn làm gì còn Cắc nào trong ATM đúng không?

Đôi khi trong quá trình thực hiện phần mềm ta có nhu cầu sao chép đối tượng ra (tạo thêm một đối tượng giống y xì đối tượng cũ nhưng nằm ở ô nhớ khác, để ta có thể tự do thay đổi thông tin trên đối tượng sao chép mà không làm ảnh hưởng tới đối tượng gốc). Kotlin hỗ trợ chúng ta hàm clone trong interface Cloneable để sao chép đối tượng:

Ta chỉnh là lớp Phân số như sau:


/**
* Created by cafe on 02/06/2017.
*/
class PhanSo:Cloneable {
var tu:Int=1
var mau:Int=1

constructor(tu: Int, mau: Int) {
this.tu = tu
this.mau = mau
}
fun copy():PhanSo
{
var ps:PhanSo=clone() as PhanSo
return ps
}
}

Ta thấy lớp Phân số kế thừa từ Cloneable  và Tui có tự bổ sung hàm copy() cho lớp phân số. hàm này đơn thuần là gọi lệnh clone() của Cloneable  để tạo ra 1 phiên bản mới của đối tượng (dữ liệu giống nhau y xì nhưng nằm trên ô nhớ khác nhau).

Trong main ta sửa lại như sau:


/**
* Created by cafe on 02/06/2017.
*/
fun main(args: Array<String>) {
var psA=PhanSo(1,5)
var psB=PhanSo(3,7)
psA=psB
println("Tử số của A="+psA.tu)
psA.tu=113
println("Tử số của B="+psB.tu)
var psC=psA.copy()
psC.tu=114
println("Tử số của A="+psA.tu)
println("Tử số của C="+psC.tu)
println("Mẫu số của C="+psC.mau)
}

Bạn thấy dòng lệnh 11 Tui gọi hàm copy và lưu vào biên psC. Chú ý ngay chỗ này nó tạo ra thêm 1 ô nhớ mới và để cho psC quản lý. Tức là psC không liên can gì tới psA và psB (lúc này psA và psB vẫn đang cùng quản lý ô nhớ B).

Như vậy khi chạy đoạn lệnh trên kết quả là gì?

Tử số của A=3
Tử số của B=113
Tử số của A=113
Tử số của C=114
Mẫu số của C=7

Bạn hiểu vì sao ra kết quả ở trên không? Tui chủ ý không giải thích nữa, để những bạn nào không hiểu thì Comment vào bài học này, những bạn hiểu sẽ giải thích cho các bạn. Nhưng Tui rất mong muốn bạn phải tự hiểu.

Như vậy tới đây Tui đã trình bày xong alias và Cơ chế gom rác tự động trong Kotlin. 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ề Extension method trong Kotlin rất là hay và rất là mới mẻ

Các bạn có thể tải source code bài này ở đây: http://www.mediafire.com/file/xx1k62gbwk2n7pk/HocGarbageCollection.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/)

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/)

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


Trong bài 24 Tui đã trình bày chi tiết các loại phương thức, tham chiếu this, overloading, parameter list… là một trong những kỹ thuật rất quan trọng trong lập trình hướng đối tượng. Trong bài này Tui tiếp tục trình bày về Data Classes, Nested Classes, Inner Classes, Enum Classes trong Kotlin là một trong những kỹ thuật khá thú vị trong lập trình hướng đối tượng và Kotlin.

1)Data Classes

Trong quá trình xử lý, ta rất thường xuyên chỉ cần lưu trữ dữ liệu mà không có các phương thức. Kotlin hỗ trợ chức năng này bằng cách giúp ta tạo một lớp đặc biệt, lớp này gọi là Data Class.

Các Data Class trong Kotlin sẽ tự động cung cấp:

  • equals() / hashCode()
  • toString()
  • componentN()
  • copy()

Ví dụ:


/**
* Created by cafe on 01/06/2017.
*/
fun main(args: Array<String>) {
data class User(var UserName:String,var Password:String)
var user1=User(UserName = "obama",Password = "113@114Xa")
var user1Copy=user1.copy()
var user2Copy=user1.copy(Password ="cohangxom" )
println(user1.toString())
println(user1Copy.toString())
println(user2Copy.toString())
println("User Name của user 1="+user1.UserName)
}

Ở dòng số 5, ta thấy một Data Class tên là User được tạo ra, nó có 2 thuộc tính là UserNamePassword

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

User(UserName=obama, Password=113@114Xa)
User(UserName=obama, Password=113@114Xa)
User(UserName=obama, Password=cohangxom)
User Name của user 1=obama

2)Nested Class

Kotlin giống như các ngôn ngữ lập trình khác, đó là khả năng cho phép Lớp này nằm trong lớp khác dạng Nested. Cần lưu ý là các lớp Nested sẽ không thể truy suất được các biến thành viên trong Outer class

ví dụ:


/**
* Created by cafe on 01/06/2017.
*/
class Outer {
private val bar: Int = 1
class Nested {
fun foo() = 113
}
}

Ở ví dụ trên thì phương thức foo() trong Nested class không thể truy suất được tới biến bar trong Outer class

Khi triệu khoi foo() ta làm như sau:


/**
* Created by cafe on 01/06/2017.
*/
fun main(args: Array<String>) {
val demo = Outer.Nested().foo()
println(demo)
}

Chạy chương trình ta sẽ được kết quả là 113 xuất ra màn hình.

3) Inner Classes

Kotlin giống như các ngôn ngữ lập trình khác, đó là khả năng cho phép Lớp này nằm trong lớp khác dạng Inner. Cần lưu ý là các lớp Inner sẽ có thể truy suất được các biến thành viên trong Outer class


package inner

/**
* Created by cafe on 01/06/2017.
*/
class Outer {
private val bar: Int = 1
inner class Inner {
fun foo() = bar
}
}

Code ở trên ta thấy dùng từ khóa inner đằng trước class Inner

hàm main sử dụng như sau:


package inner

import inner.Outer

/**
* Created by cafe on 01/06/2017.
*/
fun main(args: Array<String>) {
val demo = Outer().Inner().foo()
println(demo)
}

Chạy chương trình ta sẽ được kết quả là 1 xuất ra màn hình.

Ở đây ta để ý có sự khác biệt giữa Nested Class và Inner class cả cách khai báo cũng như cách truy suất (hãy tự để ý kỹ nó khác chỗ nào).

4)Enum Classes

Enum cũng là một loại Lớp đặc biệt trong Kotlin (giống như các ngôn ngữ khác C#, java…)

Cách khai báo Enum trong Kotlin rất đơn giản, tương tự như các ngôn ngữ lập trình khác.

Lúc new File ta chọn Kind là Enum class, Name là nơi đặt tên Enum. Ví dụ đặt là XepLoai:


enum class XepLoai {
XuatSac,Gioi,Kha,TrungBinh,Yeu,Kem
}

Ta có thể sử dụng Enum này như sau:


/**
* Created by cafe on 01/06/2017.
*/
class SinhVien {
var Ma:Int=0
var Ten:String=""
var DiemTrungBinh:Double=0.0
public fun XepLoaiHocTap():XepLoai
{
if(DiemTrungBinh>=9)return XepLoai.XuatSac
if(DiemTrungBinh>=8)return XepLoai.Gioi
if(DiemTrungBinh>=7)return XepLoai.Kha
if(DiemTrungBinh>=5)return XepLoai.TrungBinh
if(DiemTrungBinh>=3)return XepLoai.Yeu
return XepLoai.Kem
}
}

Tạo main để triệu gọi như sau:


fun main(args: Array<String>) {
var teo=SinhVien()
teo.DiemTrungBinh=9.0
println(teo.XepLoaiHocTap())
}

Chạy chương trình ta sẽ có kết quả là XuatSac.

Như vậy tới đây Tui đã trình bày xong các loại class đặc biệt trong Kotlin(Data Classes, Nested Classes, Inner Classes và Enum 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ẽ tiếp tục trình bày về OOP trong Kotlin (Kế thừa rất quan trọng), 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/8r7z95j8r9lptob/HocOOPPhan4.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/)

%d bloggers like this: