Codelab นี้เป็นส่วนหนึ่งของหลักสูตร Kotlin Bootcamp สําหรับโปรแกรมเมอร์ คุณจะได้รับประโยชน์สูงสุดจากหลักสูตรนี้ หากทํางานผ่าน Codelab ตามลําดับ คุณอาจอ่านผ่านบางหัวข้อได้ ทั้งนี้ขึ้นอยู่กับความรู้ของคุณ หลักสูตรนี้มุ่งเน้นที่โปรแกรมเมอร์ที่มีความรู้เกี่ยวกับภาษาเชิงวัตถุและต้องการเรียนรู้ Kotlin
บทนำ
ใน Codelab นี้ คุณจะสร้างโปรแกรม Kotlin แล้วเรียนรู้เกี่ยวกับชั้นเรียนและวัตถุใน Kotlin คุณจะคุ้นเคยกับเนื้อหาส่วนใหญ่นี้ ถ้าคุณรู้ภาษาเชิงวัตถุอื่น แต่ Kotlin มีความแตกต่างที่สําคัญบางประการในการลดจํานวนโค้ดที่ต้องใช้ในการเขียน รวมถึงดูข้อมูลเกี่ยวกับชั้นเรียนนามธรรมและการมอบสิทธิ์อินเทอร์เฟซ
แทนที่หลักสูตรนี้จะสร้างแอปตัวอย่างเดียว บทเรียนในหลักสูตรนี้ออกแบบมาเพื่อสร้างเสริมความรู้ แต่นักเรียนไม่ต้องพึ่งพากันและกันเพื่อให้คุณเข้าใจส่วนต่างๆ ที่คุณคุ้นเคย ตัวอย่างจํานวนมากใช้ธีมสัตว์น้ําร่วมกัน และอยากดูเรื่องราวเกี่ยวกับสัตว์น้ําทั้งหมด โปรดดูหลักสูตร Kotlin Bootcamp for Programmers Udacity
สิ่งที่ควรทราบอยู่แล้ว
- ข้อมูลเบื้องต้นของ Kotlin รวมทั้งประเภท โอเปอเรเตอร์ และการวนซ้ํา
- ไวยากรณ์ฟังก์ชันของ Kotlin's
- พื้นฐานของการเขียนโปรแกรมที่เน้นวัตถุ
- ข้อมูลพื้นฐานของ IDE เช่น IntelliJ IDEA หรือ Android Studio
สิ่งที่คุณจะได้เรียนรู้
- วิธีสร้างชั้นเรียนและเข้าถึงพร็อพเพอร์ตี้ใน Kotlin
- วิธีสร้างและใช้เครื่องมือสร้างชั้นเรียนใน Kotlin
- วิธีสร้างคลาสย่อยและวิธีการทํางานของการรับช่วงต่อ
- เกี่ยวกับชั้นเรียนนามธรรม อินเทอร์เฟซ และการมอบสิทธิ์ในอินเทอร์เฟซ
- วิธีสร้างและใช้ชั้นเรียนข้อมูล
- วิธีใช้ซิงเกิลตัน Enum และคลาสปิดผนึก
สิ่งที่คุณจะทํา
- สร้างชั้นเรียนด้วยพร็อพเพอร์ตี้
- สร้างเครื่องมือสร้างสําหรับชั้นเรียน
- สร้างคลาสย่อย
- ดูตัวอย่างคลาสและอินเทอร์เฟซนามธรรม
- สร้างคลาสข้อมูลแบบง่าย
- ดูข้อมูลเกี่ยวกับซิงเกิล Enum และคลาสปิดผนึก
ข้อกําหนดการจัดโปรแกรมต่อไปนี้ควรเป็นสิ่งที่คุณคุ้นเคยอยู่แล้ว
- ชั้นเรียนคือพิมพ์เขียวของวัตถุ เช่น คลาส
Aquarium
คือพิมพ์เขียวสําหรับสร้างวัตถุในพิพิธภัณฑ์สัตว์น้ํา - วัตถุ คืออินสแตนซ์ของคลาส วัตถุพิพิธภัณฑ์สัตว์น้ําคือ
Aquarium
ตามจริง - พร็อพเพอร์ตี้คือลักษณะของคลาส เช่น ความยาว ความกว้าง และความสูงของ
Aquarium
- Methods หรือที่เรียกว่าฟังก์ชันสมาชิกเป็นฟังก์ชันของชั้นเรียน เมธอดคือสิ่งที่คุณ "do" อยู่ได้ด้วยวัตถุ ตัวอย่างเช่น คุณจะ
fillWithWater()
ออบเจ็กต์Aquarium
ได้ - อินเทอร์เฟซคือข้อกําหนดที่ชั้นเรียนจะนําไปใช้ได้ ตัวอย่างเช่น การทําความสะอาดมักพบวัตถุอื่นนอกเหนือจาก พิพิธภัณฑ์สัตว์น้ํา และโดยทั่วไปแล้วการทําความสะอาดก็ทําในลักษณะที่คล้ายๆ กันสําหรับวัตถุต่างๆ ดังนั้น คุณอาจมีอินเทอร์เฟซที่ชื่อ
Clean
ซึ่งกําหนดเมธอดclean()
ชั้นเรียนAquarium
สามารถใช้อินเทอร์เฟซClean
เพื่อทําความสะอาดตู้ปลาด้วยฟองน้ํานิ่ม - แพ็กเกจคือวิธีจัดกลุ่มโค้ดที่เกี่ยวข้องเพื่อจัดระเบียบหรือสร้างคลังโค้ด เมื่อสร้างแพ็กเกจแล้ว คุณจะนําเข้าเนื้อหาของแพ็กเกจลงในไฟล์อื่นและนํารหัสและคลาสมาใช้ซ้ําได้
ในงานนี้ คุณจะได้สร้างแพ็กเกจและคลาสใหม่พร้อมทั้งพร็อพเพอร์ตี้และวิธีการ
ขั้นตอนที่ 1: สร้างแพ็กเกจ
แพ็กเกจช่วยให้คุณจัดระเบียบโค้ดได้
- ในแผง Project ใต้โปรเจ็กต์ สวัสดี Kotlin ให้คลิกขวาที่โฟลเดอร์ src
- เลือก New > Package และตั้งชื่อว่า
example.myapp
ขั้นตอนที่ 2: สร้างชั้นเรียนด้วยพร็อพเพอร์ตี้
ชั้นเรียนจะกําหนดด้วยคีย์เวิร์ด class
และชื่อชั้นเรียนตามแบบแผนเริ่มต้นด้วยอักษรตัวพิมพ์ใหญ่
- คลิกขวาที่แพ็กเกจ example.myapp
- เลือก New > Kotlin File / Class
- ในส่วนประเภท ให้เลือกชั้นเรียน และตั้งชื่อชั้นเรียนว่า
Aquarium
IntelliJ IDEA มีชื่อแพ็กเกจในไฟล์และสร้างคลาสAquarium
ที่ว่างเปล่าให้คุณ - ในคลาส
Aquarium
ให้กําหนดและเริ่มต้นคุณสมบัติvar
สําหรับความกว้าง ความสูง และความยาว (เป็นเซนติเมตร) เริ่มต้นพร็อพเพอร์ตี้ด้วยค่าเริ่มต้น
package example.myapp
class Aquarium {
var width: Int = 20
var height: Int = 40
var length: Int = 100
}
ภายในพร็อพเพอร์ตี้ Kotlin จะสร้าง Getter และ Setter โดยอัตโนมัติสําหรับพร็อพเพอร์ตี้ที่คุณกําหนดในชั้นเรียน Aquarium
เพื่อให้คุณเข้าถึงพร็อพเพอร์ตี้ได้โดยตรง เช่น myAquarium.length
ขั้นตอนที่ 3: สร้างฟังก์ชันหลัก()
สร้างไฟล์ใหม่ชื่อ main.kt
เพื่อเก็บฟังก์ชัน main()
- คลิกขวาที่แพ็กเกจ example.myapp ในแผงโปรเจ็กต์ทางด้านซ้าย
- เลือก New > Kotlin File / Class
- ในเมนูแบบเลื่อนลงประเภท ให้เก็บรายการที่เลือกเป็นไฟล์ และตั้งชื่อไฟล์
main.kt
IntelliJ IDEA จะรวมชื่อแพ็กเกจ แต่ไม่รวมคําจํากัดความของคลาสสําหรับไฟล์ - กําหนดฟังก์ชัน
buildAquarium()
และสร้างอินสแตนซ์ของAquarium
ภายใน ในการสร้างอินสแตนซ์ ให้อ้างอิงคลาสเสมือนเป็นฟังก์ชันAquarium()
การดําเนินการนี้จะโทรหาเครื่องมือสร้างชั้นเรียนและสร้างอินสแตนซ์ของคลาสAquarium
ซึ่งคล้ายกับการใช้new
ในภาษาอื่นๆ - กําหนดฟังก์ชัน
main()
แล้วเรียกใช้buildAquarium()
package example.myapp
fun buildAquarium() {
val myAquarium = Aquarium()
}
fun main() {
buildAquarium()
}
ขั้นตอนที่ 4: เพิ่มเมธอด
- ในชั้นเรียน
Aquarium
ให้เพิ่มวิธีพิมพ์คุณสมบัติมิติข้อมูลของพิพิธภัณฑ์สัตว์น้ํา
fun printSize() {
println("Width: $width cm " +
"Length: $length cm " +
"Height: $height cm ")
}
- ใน
main.kt
ในbuildAquarium()
ให้เรียกใช้เมธอดprintSize()
ในmyAquarium
fun buildAquarium() {
val myAquarium = Aquarium()
myAquarium.printSize()
}
- เรียกใช้โปรแกรมโดยคลิกรูปสามเหลี่ยมสีเขียวถัดจากฟังก์ชัน
main()
สังเกตผลลัพธ์
⇒ Width: 20 cm Length: 100 cm Height: 40 cm
- ใน
buildAquarium()
ให้เพิ่มโค้ดเพื่อกําหนดความสูงเป็น 60 และพิมพ์คุณสมบัติของมิติข้อมูลที่เปลี่ยนแปลง
fun buildAquarium() {
val myAquarium = Aquarium()
myAquarium.printSize()
myAquarium.height = 60
myAquarium.printSize()
}
- เรียกใช้โปรแกรมและสังเกตเอาต์พุต
⇒ Width: 20 cm Length: 100 cm Height: 40 cm Width: 20 cm Length: 100 cm Height: 60 cm
ในงานนี้ คุณจะต้องสร้างเครื่องมือสร้างสําหรับชั้นเรียนและทํางานกับพร็อพเพอร์ตี้ต่อ
ขั้นตอนที่ 1: สร้างเครื่องมือสร้าง
ในขั้นตอนนี้ ให้เพิ่มเครื่องมือสร้างไปยังชั้นเรียน Aquarium
ที่คุณสร้างในงานแรก ในตัวอย่างก่อนหน้า อินสแตนซ์ทั้งหมดของ Aquarium
จะสร้างด้วยมิติข้อมูลเดียวกัน คุณสามารถเปลี่ยนมิติข้อมูลเมื่อสร้างมิติข้อมูลด้วยการตั้งค่าพร็อพเพอร์ตี้ได้ง่ายขึ้น แต่การสร้างเริ่มต้นด้วยขนาดที่ถูกต้องจะทําได้ง่ายกว่า
ในบางภาษาโปรแกรม เครื่องมือสร้างจะกําหนดโดยการสร้างเมธอดภายในชั้นเรียนที่มีชื่อเดียวกับคลาส ใน Kotlin คุณกําหนดตัวสร้างโดยตรงในการประกาศคลาสเอง โดยระบุพารามิเตอร์ภายในวงเล็บเสมือนว่าคลาสเป็นเมธอด พารามิเตอร์เหล่านั้นสามารถใส่ค่าเริ่มต้นได้เช่นเดียวกับฟังก์ชันใน Kotlin
- ในคลาส
Aquarium
ที่คุณสร้างก่อนหน้านี้ ให้เปลี่ยนแปลงการกําหนดคลาสให้รวมพารามิเตอร์ตัวสร้าง 3 รายการที่มีค่าเริ่มต้นสําหรับlength
,width
และheight
และกําหนดให้กับพร็อพเพอร์ตี้ที่เกี่ยวข้อง
class Aquarium(length: Int = 100, width: Int = 20, height: Int = 40) {
// Dimensions in cm
var length: Int = length
var width: Int = width
var height: Int = height
...
}
- วิธี Kotlin ที่กะทัดรัดมากขึ้นคือการกําหนดพร็อพเพอร์ตี้กับเครื่องมือสร้างโดยตรงโดยใช้
var
หรือval
และ Kotlin ยังสร้าง Getter และ Setter โดยอัตโนมัติด้วย จากนั้นนําคําจํากัดความของพร็อพเพอร์ตี้ออกจากเนื้อหาในชั้นเรียนได้
class Aquarium(var length: Int = 100, var width: Int = 20, var height: Int = 40) {
...
}
- เมื่อสร้างออบเจ็กต์
Aquarium
ด้วยเครื่องมือสร้างนั้น คุณจะระบุอาร์กิวเมนต์ไม่ได้และรับค่าเริ่มต้น หรือระบุเฉพาะบางออบเจ็กต์ หรือระบุออบเจ็กต์ทั้งหมดและสร้างAquarium
ที่มีขนาดแบบกําหนดเองทั้งหมด ในฟังก์ชันbuildAquarium()
ให้ลองใช้วิธีต่างๆ ในการสร้างออบเจ็กต์Aquarium
โดยใช้พารามิเตอร์ที่มีชื่อ
fun buildAquarium() {
val aquarium1 = Aquarium()
aquarium1.printSize()
// default height and length
val aquarium2 = Aquarium(width = 25)
aquarium2.printSize()
// default width
val aquarium3 = Aquarium(height = 35, length = 110)
aquarium3.printSize()
// everything custom
val aquarium4 = Aquarium(width = 25, height = 35, length = 110)
aquarium4.printSize()
}
- เรียกใช้โปรแกรมและสังเกตเอาต์พุต
⇒ Width: 20 cm Length: 100 cm Height: 40 cm Width: 25 cm Length: 100 cm Height: 40 cm Width: 20 cm Length: 110 cm Height: 35 cm Width: 25 cm Length: 110 cm Height: 35 cm
โปรดสังเกตว่าคุณไม่ได้โหลดเครื่องมือสร้างมากเกินไปและเขียนเวอร์ชันอื่นสําหรับแต่ละกรณี (และอีก 2-3 รายการสําหรับชุดค่าผสมอื่นๆ) Kotlin สร้างสิ่งที่จําเป็นจากค่าเริ่มต้นและพารามิเตอร์ที่มีชื่อ
ขั้นตอนที่ 2: เพิ่มบล็อก init
เครื่องมือสร้างตัวอย่างด้านบนเป็นเพียงการประกาศพร็อพเพอร์ตี้ และกําหนดมูลค่าของนิพจน์ดังกล่าวเท่านั้น หากเครื่องมือสร้างของคุณจําเป็นต้องมีโค้ดการเริ่มต้นเพิ่มเติม คุณสามารถวางโค้ดไว้ในบล็อก init
อย่างน้อย 1 รายการ ในขั้นตอนนี้ คุณจะเพิ่มบล็อก init
บางบล็อกไปยัง Aquarium
ชั้นเรียน
- ในชั้นเรียน
Aquarium
ให้เพิ่มบล็อกinit
เพื่อพิมพ์ว่าวัตถุกําลังเริ่มต้นและเพิ่มบล็อกที่ 2 เพื่อพิมพ์ปริมาตรเป็นลิตร
class Aquarium (var length: Int = 100, var width: Int = 20, var height: Int = 40) {
init {
println("aquarium initializing")
}
init {
// 1 liter = 1000 cm^3
println("Volume: ${width * length * height / 1000} l")
}
}
- เรียกใช้โปรแกรมและสังเกตเอาต์พุต
aquarium initializing
Volume: 80 l
Width: 20 cm Length: 100 cm Height: 40 cm
aquarium initializing
Volume: 100 l
Width: 25 cm Length: 100 cm Height: 40 cm
aquarium initializing
Volume: 77 l
Width: 20 cm Length: 110 cm Height: 35 cm
aquarium initializing
Volume: 96 l
Width: 25 cm Length: 110 cm Height: 35 cm
โปรดสังเกตว่าบล็อก init
จะทํางานตามลําดับที่ปรากฏในคําจํากัดความของชั้นเรียน และบล็อกทั้งหมดเมื่อมีการเรียกใช้ตัวสร้าง
ขั้นตอนที่ 3: ดูข้อมูลเกี่ยวกับเครื่องมือสร้างรอง
ในขั้นตอนนี้ คุณจะได้เรียนรู้เกี่ยวกับเครื่องมือสร้างสํารองและเพิ่มลงในคลาส นอกเหนือจากเครื่องมือสร้างหลักที่มีบล็อก init
ได้อย่างน้อย 1 บล็อกแล้ว คลาส Kotlin อาจมีตัวสร้างรองอย่างน้อย 1 ตัวเพื่ออนุญาตเครื่องมือสร้างที่มากเกินไป ซึ่งก็คือตัวสร้างที่มีอาร์กิวเมนต์ต่างกัน
- ในคลาส
Aquarium
ให้เพิ่มเครื่องมือสร้างรองที่มีจํานวนปลาเป็นอาร์กิวเมนต์โดยใช้คีย์เวิร์ดconstructor
สร้างพร็อพเพอร์ตี้บ่อปลาval
สําหรับปริมาณตู้ปลาที่คํานวณได้ในหน่วยลิตรตามจํานวนปลา สมมติว่าน้ํา 2 ลิตร (2,000 ซม. 3 ลิตร) ต่อปลา และเพิ่มห้องอีกเล็กน้อยเพื่อให้น้ําหกใส่ไม่ได้
constructor(numberOfFish: Int) : this() {
// 2,000 cm^3 per fish + extra room so water doesn't spill
val tank = numberOfFish * 2000 * 1.1
}
- ในเครื่องมือสร้างรอง ให้คงความยาวและความกว้าง (ซึ่งกําหนดไว้ในตัวสร้างหลัก) ไว้เท่าเดิม และคํานวณความสูงที่จําเป็นในการทําให้ถังมีขนาดเท่ากับ
// calculate the height needed
height = (tank / (length * width)).toInt()
- เพิ่มฟังก์ชันเพื่อสร้าง
Aquarium
โดยใช้ตัวสร้างสํารองรายการใหม่ในฟังก์ชันbuildAquarium()
พิมพ์ขนาดและปริมาณ
fun buildAquarium() {
val aquarium6 = Aquarium(numberOfFish = 29)
aquarium6.printSize()
println("Volume: ${aquarium6.width * aquarium6.length * aquarium6.height / 1000} l")
}
- เรียกใช้โปรแกรมและสังเกตเอาต์พุต
⇒ aquarium initializing Volume: 80 l Width: 20 cm Length: 100 cm Height: 31 cm Volume: 62 l
โปรดสังเกตว่าพิมพ์วอลุ่ม 2 ครั้ง 1 ครั้ง ได้แก่ บล็อก init
ในเครื่องมือสร้างหลักก่อนเรียกใช้เครื่องมือสร้างรอง และ 1 ครั้งด้วยโค้ดใน buildAquarium()
คุณสามารถใส่คีย์เวิร์ด constructor
ในเครื่องมือสร้างหลักได้เช่นกัน แต่ในกรณีส่วนใหญ่แล้ว ไม่จําเป็นต้องใช้
ขั้นตอนที่ 4: เพิ่ม Getter พร็อพเพอร์ตี้ใหม่
ในขั้นตอนนี้ ให้เพิ่ม Getter พร็อพเพอร์ตี้อย่างชัดแจ้ง Kotlin กําหนด Getter และ Setter โดยอัตโนมัติเมื่อคุณกําหนดพร็อพเพอร์ตี้ แต่บางครั้งคุณจะต้องปรับเปลี่ยนหรือคํานวณค่าของพร็อพเพอร์ตี้ เช่น ด้านบนคุณพิมพ์ระดับเสียงของ Aquarium
คุณสามารถกําหนดให้วอลุ่มเป็นพร็อพเพอร์ตี้ได้โดยกําหนดตัวแปรและ Getter สําหรับตัวแปร เนื่องจากต้องมีการคํานวณ volume
Getter จึงต้องแสดงผลค่าที่คํานวณได้ซึ่งคุณใช้ฟังก์ชัน 1 บรรทัดได้
- ในชั้นเรียน
Aquarium
ให้กําหนดพร็อพเพอร์ตี้Int
ชื่อvolume
และกําหนดเมธอดget()
ที่คํานวณปริมาตรในบรรทัดถัดไป
val volume: Int
get() = width * height * length / 1000 // 1000 cm^3 = 1 l
- นําบล็อก
init
ที่พิมพ์วอลุ่มออก - นํารหัสใน
buildAquarium()
ที่พิมพ์วอลุ่มออก - ด้วยวิธีการ
printSize()
ให้เพิ่มบรรทัดเพื่อพิมพ์วอลุ่ม
fun printSize() {
println("Width: $width cm " +
"Length: $length cm " +
"Height: $height cm "
)
// 1 l = 1000 cm^3
println("Volume: $volume l")
}
- เรียกใช้โปรแกรมและสังเกตเอาต์พุต
⇒ aquarium initializing Width: 20 cm Length: 100 cm Height: 31 cm Volume: 62 l
ขนาดและปริมาตรยังคงเหมือนเดิม แต่ปริมาณจะพิมพ์เพียงครั้งเดียวเมื่อเริ่มต้นโดยทั้งเครื่องมือสร้างหลักและตัวรองรอง
ขั้นตอนที่ 5: เพิ่มตัวตั้งค่าพร็อพเพอร์ตี้
ในขั้นตอนนี้ คุณจะต้องสร้างการตั้งค่าพร็อพเพอร์ตี้ใหม่สําหรับวอลุ่ม
- ในชั้นเรียน
Aquarium
ให้เปลี่ยนvolume
เป็นvar
เพื่อให้ตั้งค่าได้มากกว่า 1 ครั้ง - เพิ่มตัวตั้งค่าสําหรับพร็อพเพอร์ตี้
volume
โดยเพิ่มเมธอดset()
ด้านล่าง Getter ซึ่งจะคํานวณความสูงอีกครั้งโดยอิงตามปริมาณน้ําที่ระบุ โดยปกติ ชื่อของพารามิเตอร์ Setter คือvalue
แต่คุณเปลี่ยนแปลงได้หากต้องการ
var volume: Int
get() = width * height * length / 1000
set(value) {
height = (value * 1000) / (width * length)
}
- ใน
buildAquarium()
ให้เพิ่มโค้ดเพื่อตั้งค่าระดับเสียงสําหรับตู้ปลาเป็น 70 ลิตร พิมพ์ขนาดใหม่
fun buildAquarium() {
val aquarium6 = Aquarium(numberOfFish = 29)
aquarium6.printSize()
aquarium6.volume = 70
aquarium6.printSize()
}
- เรียกใช้โปรแกรมอีกครั้งและสังเกตความสูงและระดับเสียงที่เปลี่ยนไป
⇒ aquarium initialized
Width: 20 cm Length: 100 cm Height: 31 cm
Volume: 62 l
Width: 20 cm Length: 100 cm Height: 35 cm
Volume: 70 l
ยังไม่มีตัวแก้ไขการปรับเปลี่ยน เช่น public
หรือ private
ในโค้ด นั่นเป็นเพราะค่าเริ่มต้นทั้งหมดของทุกอย่างใน Kotlin คือสาธารณะ ซึ่งหมายความว่าทุกอย่างจะเข้าถึงได้ทุกที่ รวมถึงคลาส เมธอด พร็อพเพอร์ตี้ และตัวแปรสมาชิก
ใน Kotlin คลาส ออบเจ็กต์ อินเทอร์เฟซ เครื่องมือสร้าง ฟังก์ชัน พร็อพเพอร์ตี้ และตัวตั้งค่าจะมีตัวปรับแต่งระดับการเข้าถึงได้ ดังนี้
public
หมายถึงแสดงต่อผู้ใช้ภายนอกชั้นเรียน ข้อมูลทุกอย่างจะเป็นแบบสาธารณะโดยค่าเริ่มต้น รวมถึงตัวแปรและวิธีการในชั้นเรียนinternal
หมายความว่าจะแสดงภายในโมดูลนั้นเท่านั้น โมดูลคือชุดไฟล์ Kotlin ที่คอมไพล์ไว้ด้วยกัน เช่น ไลบรารีหรือแอปพลิเคชันprivate
หมายความว่าจะปรากฏในชั้นเรียนดังกล่าวเท่านั้น (หรือไฟล์ต้นฉบับหากคุณใช้งานฟังก์ชัน)protected
เหมือนกับprivate
แต่จะปรากฏแก่คลาสย่อยด้วย
ดูข้อมูลเพิ่มเติมได้ที่ตัวปรับแต่งระดับการเข้าถึงในเอกสาร Kotlin
ตัวแปรสมาชิก
พร็อพเพอร์ตี้ภายในชั้นเรียนหรือตัวแปรสมาชิกจะมีค่าเริ่มต้นเป็น public
หากกําหนดด้วย var
ก็จะเปลี่ยนแปลงได้ ทั้งอ่านและเขียนได้ หากกําหนดโดยใช้ val
นโยบายจะเป็นแบบอ่านอย่างเดียวหลังจากการเริ่มต้น
หากต้องการให้พร็อพเพอร์ตี้อ่านหรือเขียนโค้ดได้ แต่โค้ดภายนอกจะอ่านได้อย่างเดียว คุณปล่อยพร็อพเพอร์ตี้และ Getter ให้เป็นสาธารณะและประกาศตัวตั้งค่าได้ดังที่แสดงด้านล่าง
var volume: Int
get() = width * height * length / 1000
private set(value) {
height = (value * 1000) / (width * length)
}
ในงานนี้ คุณจะได้ศึกษาวิธีการทํางานของคลาสย่อยและการสืบทอดใน Kotlin ซึ่งคล้ายกับภาษาที่คุณเห็นในภาษาอื่น แต่มีข้อแตกต่างบางประการ
ใน Kotlin โดยค่าเริ่มต้นจะเป็นคลาสย่อยไม่ได้ ในทํานองเดียวกัน คลาสย่อยและตัวแปรสมาชิกจะถูกลบล้างไม่ได้ (แต่จะเข้าถึงได้)
คุณต้องทําเครื่องหมายชั้นเรียนเป็น open
เพื่ออนุญาตชั้นเรียนย่อย ในทํานองเดียวกัน คุณต้องทําเครื่องหมายพร็อพเพอร์ตี้และตัวแปรสมาชิกเป็น open
เพื่อลบล้างค่าเหล่านี้ในคลาสย่อย ต้องใช้คีย์เวิร์ด open
เพื่อป้องกันไม่ให้รายละเอียดการใช้งานรั่วไหลโดยไม่ได้ตั้งใจโดยเป็นส่วนหนึ่งของอินเทอร์เฟซของคลาส
ขั้นตอนที่ 1: เปิดชั้นเรียนตู้ปลา
ในขั้นตอนนี้ คุณจะสร้างชั้นเรียน Aquarium
open
เพื่อลบล้างในขั้นตอนถัดไป
- ทําเครื่องหมายคลาส
Aquarium
และพร็อพเพอร์ตี้ทั้งหมดด้วยคีย์เวิร์ดopen
open class Aquarium (open var length: Int = 100, open var width: Int = 20, open var height: Int = 40) {
open var volume: Int
get() = width * height * length / 1000
set(value) {
height = (value * 1000) / (width * length)
}
- เพิ่มพร็อพเพอร์ตี้
shape
ที่เปิดอยู่ซึ่งมีค่า"rectangle"
open val shape = "rectangle"
- เพิ่มพร็อพเพอร์ตี้
water
แบบเปิดที่มี Getter ที่แสดง 90% ของปริมาณของAquarium
open var water: Double = 0.0
get() = volume * 0.9
- เพิ่มโค้ดลงในเมธอด
printSize()
เพื่อพิมพ์รูปร่างและปริมาณน้ําเป็นเปอร์เซ็นต์ของปริมาตร
fun printSize() {
println(shape)
println("Width: $width cm " +
"Length: $length cm " +
"Height: $height cm ")
// 1 l = 1000 cm^3
println("Volume: $volume l Water: $water l (${water/volume*100.0}% full)")
}
- ใน
buildAquarium()
เปลี่ยนโค้ดเพื่อสร้างAquarium
ที่มีwidth = 25
,length = 25
และheight = 40
fun buildAquarium() {
val aquarium6 = Aquarium(length = 25, width = 25, height = 40)
aquarium6.printSize()
}
- เรียกใช้โปรแกรมและสังเกตเอาต์พุตใหม่
⇒ aquarium initializing rectangle Width: 25 cm Length: 25 cm Height: 40 cm Volume: 25 l Water: 22.5 l (90.0% full)
ขั้นตอนที่ 2: สร้างคลาสย่อย
- สร้างคลาสย่อยของ
Aquarium
ที่ชื่อTowerTank
ซึ่งใช้ถังทรงกลมแทนถังทรงสี่เหลี่ยมผืนผ้า คุณสามารถเพิ่มTowerTank
ด้านล่างAquarium
ได้ เนื่องจากคุณเพิ่มชั้นเรียนอื่นในไฟล์เดียวกับชั้นเรียนของAquarium
ได้ - ใน
TowerTank
ให้ลบล้างพร็อพเพอร์ตี้height
ซึ่งกําหนดไว้ในเครื่องมือสร้าง หากต้องการลบล้างพร็อพเพอร์ตี้ ให้ใช้คีย์เวิร์ดoverride
ในคลาสย่อย
- ทําให้เครื่องมือสร้างสําหรับ
TowerTank
ใช้diameter
ใช้diameter
สําหรับทั้งlength
และwidth
เมื่อเรียกใช้เครื่องมือสร้างในซูเปอร์คลาสAquarium
class TowerTank (override var height: Int, var diameter: Int): Aquarium(height = height, width = diameter, length = diameter) {
- ลบล้างพร็อพเพอร์ตี้ระดับเสียงเพื่อคํานวณทรงกระบอก สูตรสําหรับทรงกระบอกคือพายคูณรัศมียกกําลัง 2 คูณความสูง คุณต้องนําเข้าค่าคงที่
PI
จากjava.lang.Math
override var volume: Int
// ellipse area = π * r1 * r2
get() = (width/2 * length/2 * height / 1000 * PI).toInt()
set(value) {
height = ((value * 1000 / PI) / (width/2 * length/2)).toInt()
}
- ใน
TowerTank
ให้ลบล้างพร็อพเพอร์ตี้water
เป็น 80% ของระดับเสียง
override var water = volume * 0.8
- ลบล้าง
shape
เป็น"cylinder"
override val shape = "cylinder"
- คลาส
TowerTank
สุดท้ายควรมีลักษณะคล้ายกับโค้ดด้านล่าง
Aquarium.kt
:
package example.myapp
import java.lang.Math.PI
... // existing Aquarium class
class TowerTank (override var height: Int, var diameter: Int): Aquarium(height = height, width = diameter, length = diameter) {
override var volume: Int
// ellipse area = π * r1 * r2
get() = (width/2 * length/2 * height / 1000 * PI).toInt()
set(value) {
height = ((value * 1000 / PI) / (width/2 * length/2)).toInt()
}
override var water = volume * 0.8
override val shape = "cylinder"
}
- ใน
buildAquarium()
ให้สร้างTowerTank
ซึ่งมีเส้นผ่านศูนย์กลาง 25 ซม. และสูง 45 ซม. พิมพ์ขนาด
main.kt:
package example.myapp
fun buildAquarium() {
val myAquarium = Aquarium(width = 25, length = 25, height = 40)
myAquarium.printSize()
val myTower = TowerTank(diameter = 25, height = 40)
myTower.printSize()
}
- เรียกใช้โปรแกรมและสังเกตเอาต์พุต
⇒ aquarium initializing rectangle Width: 25 cm Length: 25 cm Height: 40 cm Volume: 25 l Water: 22.5 l (90.0% full) aquarium initializing cylinder Width: 25 cm Length: 25 cm Height: 40 cm Volume: 18 l Water: 14.4 l (80.0% full)
บางครั้งคุณต้องการกําหนดพฤติกรรมทั่วไปหรือพร็อพเพอร์ตี้ที่จะแชร์ไปยังชั้นเรียนที่เกี่ยวข้องบางชั้น Kotlin มี 2 วิธีที่ทําได้คือ อินเทอร์เฟซและชั้นเรียนนามธรรม ในงานนี้ คุณจะได้สร้างคลาส AquariumFish
นามธรรมสําหรับพร็อพเพอร์ตี้ที่มักพบในปลาทั้งหมด คุณสร้างอินเทอร์เฟซชื่อ FishAction
เพื่อกําหนดลักษณะการทํางานทั่วไปสําหรับปลาทั้งหมด
- จะไม่สามารถแยกคลาสที่เป็นนามธรรมและอินเทอร์เฟซด้วยตนเองได้ ซึ่งหมายความว่าคุณสร้างออบเจ็กต์ประเภทเหล่านั้นโดยตรงไม่ได้
- ชั้นเรียนนามธรรมมีเครื่องมือสร้าง
- อินเทอร์เฟซต้องไม่มีตรรกะตัวสร้างหรือจัดเก็บสถานะใดๆ
ขั้นตอนที่ 1 สร้างชั้นเรียนนามธรรม
- สร้างไฟล์ใหม่ชื่อ
AquariumFish.kt
ใน example.myapp - สร้างชั้นเรียนหรือที่เรียกว่า
AquariumFish
และทําเครื่องหมายด้วยabstract
- เพิ่มพร็อพเพอร์ตี้
String
ที่ชื่อcolor
และทําเครื่องหมายด้วยabstract
package example.myapp
abstract class AquariumFish {
abstract val color: String
}
- สร้างชั้นเรียนย่อยของ
AquariumFish
,Shark
และPlecostomus
- เนื่องจาก
color
เป็นนามธรรม คลาสย่อยจึงต้องนําไปใช้ ทําให้Shark
เป็นสีเทาและPlecostomus
สีทอง
class Shark: AquariumFish() {
override val color = "gray"
}
class Plecostomus: AquariumFish() {
override val color = "gold"
}
- ใน main.kt ให้สร้างฟังก์ชัน
makeFish()
เพื่อทดสอบชั้นเรียน ระบุShark
และPlecostomus
แล้วพิมพ์สีของแต่ละรายการ - ลบรหัสการทดสอบก่อนหน้านี้ใน
main()
และเพิ่มการโทรไปที่makeFish()
โค้ดควรมีลักษณะดังนี้
main.kt
:
package example.myapp
fun makeFish() {
val shark = Shark()
val pleco = Plecostomus()
println("Shark: ${shark.color}")
println("Plecostomus: ${pleco.color}")
}
fun main () {
makeFish()
}
- เรียกใช้โปรแกรมและสังเกตเอาต์พุต
⇒ Shark: gray Plecostomus: gold
แผนภาพต่อไปนี้แสดงคลาส Shark
และ Plecostomus
ซึ่งเป็นคลาสย่อยของนามธรรม AquariumFish
ขั้นตอนที่ 2 สร้างอินเทอร์เฟซ
- ใน AquariumFish.kt ให้สร้างอินเทอร์เฟซชื่อ
FishAction
ด้วยเมธอดeat()
interface FishAction {
fun eat()
}
- เพิ่ม
FishAction
ลงในแต่ละคลาสย่อยและใช้eat()
โดยพิมพ์สิ่งที่ปลาทํา
class Shark: AquariumFish(), FishAction {
override val color = "gray"
override fun eat() {
println("hunt and eat fish")
}
}
class Plecostomus: AquariumFish(), FishAction {
override val color = "gold"
override fun eat() {
println("eat algae")
}
}
- ในฟังก์ชัน
makeFish()
ให้ปลาแต่ละตัวที่คุณสร้างกินบางอย่างด้วยการเรียกeat()
fun makeFish() {
val shark = Shark()
val pleco = Plecostomus()
println("Shark: ${shark.color}")
shark.eat()
println("Plecostomus: ${pleco.color}")
pleco.eat()
}
- เรียกใช้โปรแกรมและสังเกตเอาต์พุต
⇒ Shark: gray hunt and eat fish Plecostomus: gold eat algae
แผนภาพต่อไปนี้แสดงคลาส Shark
และคลาส Plecostomus
ซึ่งทั้ง 2 รายการนี้ประกอบขึ้นและใช้อินเทอร์เฟซ FishAction
กรณีที่ควรใช้ชั้นเรียนนามธรรมและอินเทอร์เฟซ
ตัวอย่างข้างต้นก็เรียบง่าย แต่เมื่อคุณมีชั้นเรียนที่เกี่ยวโยงกันเป็นจํานวนมาก ชั้นเรียนและนามธรรมที่มีนามธรรมจะช่วยให้คุณออกแบบให้สะอาดตา เป็นระเบียบมากขึ้น และดูแลรักษาได้ง่ายขึ้น
ดังที่ระบุไว้ข้างต้น ชั้นเรียนในนามธรรมอาจมีเครื่องมือสร้างและอินเทอร์เฟซได้ แต่อินเทอร์เฟซจะมีความคล้ายคลึงกันอย่างมาก เราควรใช้แต่ละรายการเมื่อใด
เมื่อใช้อินเทอร์เฟซในการเขียนชั้นเรียน ระบบจะขยายฟังก์ชันการทํางานของคลาสตามอินสแตนซ์ของชั้นเรียนที่มี การเรียบเรียงมีแนวโน้มที่จะทําให้โค้ดใช้ซ้ําและเหตุผลได้มากกว่าการสืบทอดจากคลาสนามธรรม นอกจากนี้คุณยังใช้อินเทอร์เฟซหลายรายการในชั้นเรียนหนึ่งชั้นเรียนได้อีกด้วย แต่สามารถย่อยได้เฉพาะจากนามธรรมเดียว
การเรียบเรียงเพลงมักทําให้การสรุปเนื้อหาดีขึ้น ทําให้การเชื่อมต่อ (สอดคล้องกัน) อินเทอร์เฟซดูสะอาดตามากขึ้น และโค้ดที่ใช้งานได้มากขึ้น ด้วยเหตุนี้ การใช้การออกแบบร่วมกับอินเทอร์เฟซจึงเป็นการออกแบบที่แนะนํามากกว่า ในทางตรงกันข้าม มรดกจากชั้นเรียนเชิงนามธรรมมักจะเหมาะสมกับปัญหาบางอย่าง ดังนั้น คุณจึงควรเลือกใช้การเรียบเรียง แต่เมื่อการสืบทอดรู้สึกว่า Kotlin ก็สามารถทําแบบนั้นได้ด้วยเช่นกัน
- ใช้อินเทอร์เฟซหากคุณมีวิธีการหลายอย่างและการใช้ค่าเริ่มต้น 1 หรือ 2 รายการ เช่น ใน
AquariumAction
ด้านล่าง
interface AquariumAction {
fun eat()
fun jump()
fun clean()
fun catchFish()
fun swim() {
println("swim")
}
}
- ใช้ชั้นเรียนนามธรรมได้ทุกเมื่อในชั้นเรียน เช่น การกลับไปที่ชั้นเรียน
AquariumFish
อาจทําให้AquariumFish
ทั้งหมดใช้FishAction
และให้การใช้งานeat
เริ่มต้นในขณะที่ใช้งานนามธรรมcolor
ได้ด้วย เนื่องจากไม่มีสีเริ่มต้นจริงๆ สําหรับปลา
interface FishAction {
fun eat()
}
abstract class AquariumFish: FishAction {
abstract val color: String
override fun eat() = println("yum")
}
งานก่อนหน้านี้ได้แนะนําชั้นเรียนเชิงนามธรรม อินเทอร์เฟซ และแนวคิดการประพันธ์ การมอบสิทธิ์อินเทอร์เฟซคือเทคนิคขั้นสูงที่ออบเจ็กต์ผู้ช่วย (หรือผู้รับมอบสิทธิ์) จะใช้เมธอดของอินเทอร์เฟซ ซึ่งชั้นเรียนจะใช้หลังจากนั้น เทคนิคนี้จะมีประโยชน์เมื่อใช้อินเทอร์เฟซในชุดชั้นเรียนที่ไม่เกี่ยวข้อง กล่าวคือคุณเพิ่มฟังก์ชันการทํางานที่จําเป็นของอินเทอร์เฟซให้กับชั้นเรียนผู้ช่วยแยกต่างหาก และแต่ละชั้นเรียนจะใช้อินสแตนซ์ของคลาสผู้ช่วยในการใช้ฟังก์ชันได้
ในงานนี้ คุณจะใช้การมอบสิทธิ์อินเทอร์เฟซเพื่อเพิ่มฟังก์ชันให้กับชั้นเรียน
ขั้นตอนที่ 1: สร้างอินเทอร์เฟซใหม่
- ในคลาส AquariumFish.kt ให้นําคลาส
AquariumFish
ออกPlecostomus
และShark
จะรับค่าเดิมจากคลาสAquariumFish
ไปใช้อินเทอร์เฟซกับการดําเนินการของปลาและสี - สร้างอินเทอร์เฟซใหม่
FishColor
ที่กําหนดสีเป็นสตริง
interface FishColor {
val color: String
}
- เปลี่ยน
Plecostomus
เพื่อใช้อินเทอร์เฟซ 2 รายการ ได้แก่FishAction
และFishColor
คุณต้องลบล้างcolor
จากFishColor
และeat()
จากFishAction
class Plecostomus: FishAction, FishColor {
override val color = "gold"
override fun eat() {
println("eat algae")
}
}
- เปลี่ยนคลาส
Shark
เพื่อใช้อินเทอร์เฟซ 2 รายการได้แก่FishAction
และFishColor
แทนการรับค่าจากAquariumFish
class Shark: FishAction, FishColor {
override val color = "gray"
override fun eat() {
println("hunt and eat fish")
}
}
- โค้ดที่เสร็จแล้วควรจะมีลักษณะดังนี้
package example.myapp
interface FishAction {
fun eat()
}
interface FishColor {
val color: String
}
class Plecostomus: FishAction, FishColor {
override val color = "gold"
override fun eat() {
println("eat algae")
}
}
class Shark: FishAction, FishColor {
override val color = "gray"
override fun eat() {
println("hunt and eat fish")
}
}
ขั้นตอนที่ 2: สร้างชั้นเรียนเดียว
ต่อไป คุณจะทําการตั้งค่าสําหรับส่วนการมอบสิทธิ์โดยสร้างคลาสผู้ช่วยเหลือที่นํา FishColor
ไปใช้ คุณสร้างชั้นเรียนพื้นฐานชื่อ GoldColor
ที่ใช้ FishColor
เพียงแต่บอกว่ามีสีเป็นสีทอง
การสร้าง GoldColor
หลายอินสแตนซ์เป็นเรื่องที่ไม่เหมาะสม เนื่องจากทั้ง 2 อย่างนี้เหมือนกันทุกประการ ดังนั้น Kotlin จึงให้คุณประกาศคลาสที่คุณสามารถสร้างอินสแตนซ์ได้เพียง 1 อินสแตนซ์โดยใช้คีย์เวิร์ด object
แทน class
Kotlin จะสร้างอินสแตนซ์นั้น 1 รายการ และอินสแตนซ์ดังกล่าวอ้างอิงโดยชื่อคลาส จากนั้นออบเจ็กต์อื่นๆ ทั้งหมดจะใช้อินสแตนซ์นี้ได้เพียงครั้งเดียว จะไม่สามารถสร้างอินสแตนซ์อื่นๆ ของคลาสนี้ได้ หากคุณคุ้นเคยกับรูปแบบซิงเกิลตัน นี่คือวิธีการนํา Singleton มาใช้ใน Kotlin
- ใน AquariumFish.kt ให้สร้างออบเจ็กต์สําหรับ
GoldColor
ลบล้างสี
object GoldColor : FishColor {
override val color = "gold"
}
ขั้นตอนที่ 3: เพิ่มการมอบสิทธิ์อินเทอร์เฟซสําหรับ FishColor
ขณะนี้คุณพร้อมที่จะใช้การมอบสิทธิ์อินเทอร์เฟซแล้ว
- ใน AquariumFish.kt ให้นําการลบล้างของ
color
ออกจากPlecostomus
- เปลี่ยนคลาส
Plecostomus
เพื่อใช้สีจากGoldColor
ซึ่งทําได้โดยเพิ่มby GoldColor
ไปยังการประกาศชั้นเรียนเพื่อสร้างการมอบสิทธิ์ แทนที่จะใช้FishColor
ให้ติดตั้งใช้งานตามGoldColor
ดังนั้นทุกครั้งที่มีการเข้าถึงcolor
ระบบจึงให้สิทธิ์แก่GoldColor
class Plecostomus: FishAction, FishColor by GoldColor {
override fun eat() {
println("eat algae")
}
}
ตามระดับชั้น Pleco ทั้งหมดจะเป็นสีทอง แต่จริงๆ แล้วปลาพวกนี้มีหลายสี คุณสามารถแก้ไขปัญหานี้ได้โดยเพิ่มพารามิเตอร์เครื่องมือสร้างสีโดย GoldColor
เป็นสีเริ่มต้นสําหรับ Plecostomus
- เปลี่ยนคลาส
Plecostomus
ให้ผ่านในfishColor
ด้วยเครื่องมือสร้าง และตั้งเป็นค่าเริ่มต้นเป็นGoldColor
เปลี่ยนการมอบสิทธิ์จากby GoldColor
เป็นby fishColor
class Plecostomus(fishColor: FishColor = GoldColor): FishAction,
FishColor by fishColor {
override fun eat() {
println("eat algae")
}
}
ขั้นตอนที่ 4: เพิ่มการมอบสิทธิ์อินเทอร์เฟซสําหรับ FishAction
คุณสามารถใช้การมอบสิทธิ์อินเทอร์เฟซสําหรับ FishAction
ในลักษณะเดียวกันได้
- ใน AquariumFish.kt สร้างคลาส
PrintingFishAction
ที่ใช้FishAction
ซึ่งต้องใช้String
food
และพิมพ์สิ่งที่ปลากิน
class PrintingFishAction(val food: String) : FishAction {
override fun eat() {
println(food)
}
}
- ในคลาส
Plecostomus
ให้นําฟังก์ชันการลบล้างeat()
ออก เนื่องจากคุณจะแทนที่ด้วยการมอบสิทธิ์ - ในการประกาศ
Plecostomus
ระบบจะมอบสิทธิ์FishAction
ให้PrintingFishAction
โดยผ่าน"eat algae"
- เมื่อใช้การมอบสิทธิ์ดังกล่าว จะไม่มีโค้ดในส่วนเนื้อหาของคลาส
Plecostomus
ดังนั้นให้นํา{}
ออก เนื่องจากการลบล้างทั้งหมดจะดําเนินการโดยการมอบสิทธิ์อินเทอร์เฟซ
class Plecostomus (fishColor: FishColor = GoldColor):
FishAction by PrintingFishAction("eat algae"),
FishColor by fishColor
แผนภาพต่อไปนี้แสดงคลาส Shark
และ Plecostomus
ซึ่งประกอบด้วยอินเทอร์เฟซ PrintingFishAction
และ FishColor
แต่มอบสิทธิ์ในการใช้งาน
การมอบสิทธิ์อินเทอร์เฟซนั้นมีประสิทธิภาพมาก และโดยปกติคุณควรเลือกวิธีการใช้งานเมื่อใดก็ตามที่ใช้ชั้นเรียนนามธรรมในภาษาอื่น วิธีนี้จะช่วยให้คุณใช้การจัดองค์ประกอบในลักษณะการทํางานต่างๆ ได้ แทนที่จะต้องจัดคลาสย่อยจํานวนมาก โดยที่แต่ละคลาสมีความเชี่ยวชาญแตกต่างกัน
คลาสข้อมูลคล้ายกับ struct
ในภาษาอื่นๆ โดยหลักๆ แล้วจะมีการคงไว้ชั่วคราวข้อมูลบางอย่าง แต่ออบเจ็กต์คลาสข้อมูลยังคงเป็นออบเจ็กต์ ออบเจ็กต์คลาสข้อมูล Kotlin มีประโยชน์เพิ่มเติมบางอย่าง เช่น ยูทิลิตีสําหรับการพิมพ์และการคัดลอก ในงานนี้ คุณจะได้สร้างคลาสข้อมูลแบบง่ายๆ และเรียนรู้เกี่ยวกับการสนับสนุนที่ Kotlin มอบให้สําหรับประเภทข้อมูล
ขั้นตอนที่ 1: สร้างคลาสข้อมูล
- เพิ่มแพ็กเกจใหม่
decor
ไว้ในแพ็กเกจ example.myapp เพื่อเก็บรหัสใหม่ คลิกขวาที่ example.myapp ในแผงโปรเจ็กต์ แล้วเลือกไฟล์ > ใหม่ > แพ็กเกจ - ในแพ็กเกจ ให้สร้างชั้นเรียนใหม่ชื่อ
Decoration
package example.myapp.decor
class Decoration {
}
- หากต้องการทําให้
Decoration
เป็นคลาสข้อมูล ให้เพิ่มคํานําหน้าdata
ด้วยการประกาศคลาส - เพิ่มพร็อพเพอร์ตี้
String
ชื่อrocks
เพื่อให้ข้อมูลบางอย่างแก่ชั้นเรียน
data class Decoration(val rocks: String) {
}
- ภายนอกไฟล์ ให้เพิ่มฟังก์ชัน
makeDecorations()
เพื่อสร้างและพิมพ์อินสแตนซ์ของDecoration
ด้วย"granite"
fun makeDecorations() {
val decoration1 = Decoration("granite")
println(decoration1)
}
- เพิ่มฟังก์ชัน
main()
เพื่อเรียกmakeDecorations()
และเรียกใช้โปรแกรมของคุณ สังเกตผลลัพธ์ที่เหมาะสมซึ่งระบบสร้างขึ้นเพราะเป็นคลาสข้อมูล
⇒ Decoration(rocks=granite)
- ใน
makeDecorations()
ให้สร้างอินสแตนซ์ออบเจ็กต์Decoration
อีก 2 รายการที่เป็นทั้ง "slate" และพิมพ์
fun makeDecorations() {
val decoration1 = Decoration("granite")
println(decoration1)
val decoration2 = Decoration("slate")
println(decoration2)
val decoration3 = Decoration("slate")
println(decoration3)
}
- ใน
makeDecorations()
ให้เพิ่มคําสั่งรูปอัดที่พิมพ์ผลลัพธ์ของการเปรียบเทียบdecoration1
กับdecoration2
และคําสั่งที่ 2 เพื่อเปรียบเทียบdecoration3
กับdecoration2
ให้ใช้เมธอด equals() ที่ได้จากคลาสข้อมูล
println (decoration1.equals(decoration2))
println (decoration3.equals(decoration2))
- เรียกใช้โค้ด
⇒ Decoration(rocks=granite) Decoration(rocks=slate) Decoration(rocks=slate) false true
ขั้นตอนที่ 2 ใช้การทําลาย
หากต้องการเข้าถึงพร็อพเพอร์ตี้ของออบเจ็กต์ข้อมูลและกําหนดให้กับตัวแปร คุณอาจกําหนดออบเจ็กต์เหล่านั้นทีละ 1 รายการก็ได้ ดังนี้
val rock = decoration.rock
val wood = decoration.wood
val diver = decoration.diver
แต่คุณสามารถสร้างตัวแปร 1 รายการสําหรับแต่ละพร็อพเพอร์ตี้ และกําหนดออบเจ็กต์ข้อมูลให้กับกลุ่มตัวแปรนั้นแทน Kotlin ป้อนค่าพร็อพเพอร์ตี้ในแต่ละตัวแปร
val (rock, wood, diver) = decoration
เราเรียกสิ่งนี้ว่าการทําลายและเป็นการสรุปสั้นๆ ที่มีประโยชน์ จํานวนตัวแปรควรตรงกับจํานวนพร็อพเพอร์ตี้ และกําหนดตัวแปรตามลําดับที่ประกาศในชั้นเรียน ลองดูตัวอย่างที่สมบูรณ์ใน Decoration.kt
// Here is a data class with 3 properties.
data class Decoration2(val rocks: String, val wood: String, val diver: String){
}
fun makeDecorations() {
val d5 = Decoration2("crystal", "wood", "diver")
println(d5)
// Assign all properties to variables.
val (rock, wood, diver) = d5
println(rock)
println(wood)
println(diver)
}
⇒ Decoration2(rocks=crystal, wood=wood, diver=diver) crystal wood diver
หากไม่ต้องการใช้พร็อพเพอร์ตี้อย่างน้อย 1 รายการ คุณจะข้ามพร็อพเพอร์ตี้ได้โดยใช้ _
แทนชื่อตัวแปรดังที่แสดงในโค้ดด้านล่าง
val (rock, _, diver) = d5
ในงานนี้ คุณจะได้เรียนรู้เกี่ยวกับคลาสเรียนพิเศษบางคลาสใน Kotlin ได้แก่
- ชั้นเรียน Singleton
- Enum
- ชั้นเรียนปิดบังหน้าเว็บจริง
ขั้นตอนที่ 1: เรียกคืนชั้นเรียนเดี่ยว
จําตัวอย่างก่อนหน้านี้ด้วยคลาส GoldColor
object GoldColor : FishColor {
override val color = "gold"
}
เนื่องจากอินสแตนซ์ทั้งหมดของ GoldColor
ทําแบบเดียวกัน จึงมีการประกาศเป็น object
แทนที่จะเป็น class
เพื่อให้เป็นรายการเดียว และมีได้เพียงอินสแตนซ์เดียว
ขั้นตอนที่ 2: สร้าง Enum
Kotlin รองรับ enum ด้วย ซึ่งช่วยให้คุณแจกแจงรายละเอียดและอ้างอิงถึงชื่อได้เหมือนกับภาษาอื่น ประกาศ Enum ด้วยการประกาศคํานําหน้าด้วยคีย์เวิร์ด enum
การประกาศ enum พื้นฐานต้องการรายชื่อเท่านั้น แต่คุณยังกําหนดช่องอย่างน้อย 1 ช่องที่เกี่ยวข้องกับชื่อแต่ละชื่อได้ด้วย
- ใน Decoration.kt ให้ลองใช้ตัวอย่าง enum
enum class Color(val rgb: Int) {
RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF);
}
ตัวเลขจะคล้ายกับรายการเดียว โดยใส่ได้เพียง 1 ค่าเท่านั้น และแต่ละรายการมีค่าในการแจกแจง ตัวอย่างเช่น คุณจะมี Color.RED
, 1 Color.GREEN
และ Color.BLUE
ได้เพียง 1 รายการเท่านั้น ในตัวอย่างนี้ ระบบจะกําหนดค่า RGB ให้กับพร็อพเพอร์ตี้ rgb
เพื่อแสดงคอมโพเนนต์สี นอกจากนี้คุณยังได้รับค่าตามลําดับฐานของ Enum โดยใช้พร็อพเพอร์ตี้ ordinal
และชื่อของพร็อพเพอร์ตี้โดยใช้พร็อพเพอร์ตี้ name
ได้ด้วย
- ลองใช้อีกตัวอย่างหนึ่งของ Enum
enum class Direction(val degrees: Int) {
NORTH(0), SOUTH(180), EAST(90), WEST(270)
}
fun main() {
println(Direction.EAST.name)
println(Direction.EAST.ordinal)
println(Direction.EAST.degrees)
}
⇒ EAST 2 90
ขั้นตอนที่ 3: สร้างชั้นเรียนที่ปิดบังหน้าเว็บจริง
ชั้นเรียนที่ปิดบังหน้าเว็บจริงคือชั้นเรียนที่แบ่งย่อยได้ แต่ต้องอยู่ในไฟล์ที่ประกาศไว้เท่านั้น ระบบจะแสดงข้อผิดพลาดหากพยายามเลือกชั้นเรียนย่อยในไฟล์อื่น
เนื่องจากคลาสและคลาสย่อยอยู่ในไฟล์เดียวกัน Kotlin จะทราบคลาสย่อยทั้งหมดแบบคงที่ เมื่อถึงตอนคอมไพเลอร์ คอมไพเลอร์จะเห็นคลาสและคลาสย่อยทั้งหมด และรู้ว่านี่คือทั้งหมดเพื่อให้คอมไพเลอร์ดําเนินการตรวจสอบให้คุณได้มากขึ้น
- ใน AquariumFish.kt ลองดูตัวอย่างคลาสที่ปิดบังหน้าเว็บจริงโดยการรักษาธีมน้ํา
sealed class Seal
class SeaLion : Seal()
class Walrus : Seal()
fun matchSeal(seal: Seal): String {
return when(seal) {
is Walrus -> "walrus"
is SeaLion -> "sea lion"
}
}
ระบบเรียนคลาส Seal
ในระดับย่อยในไฟล์อื่นไม่ได้ หากต้องการเพิ่ม Seal
ประเภท คุณต้องเพิ่มประเภทอื่นๆ ไว้ในไฟล์เดียวกัน วิธีนี้ทําให้ชั้นเรียนที่ปิดผนึกเป็นวิธีที่ปลอดภัยในการนําเสนอประเภทได้หลายประเภท เช่น คลาสที่ปิดผนึกได้นั้นเหมาะสําหรับความสําเร็จหรือข้อผิดพลาดเกี่ยวกับการคืนสินค้าจาก API เครือข่าย
บทเรียนนี้ครอบคลุมเรื่องมากมาย แม้ว่าภาษาส่วนใหญ่น่าจะทําความคุ้นเคยกับภาษาโปรแกรมอื่นๆ ที่เน้นวัตถุ แต่ Kotlin เพิ่มฟีเจอร์บางอย่างเพื่อให้โค้ดกระชับและอ่านได้ง่าย
ชั้นเรียนและเครื่องมือสร้าง
- กําหนดชั้นเรียนใน Kotlin โดยใช้
class
- Kotlin สร้าง Setter และ Getter สําหรับพร็อพเพอร์ตี้โดยอัตโนมัติ
- กําหนดตัวสร้างหลักโดยตรงในคํานิยามของชั้นเรียน ดังตัวอย่างต่อไปนี้
class Aquarium(var length: Int = 100, var width: Int = 20, var height: Int = 40)
- หากเครื่องมือสร้างหลักต้องการโค้ดเพิ่มเติม ให้เขียนโค้ดไว้ในบล็อก
init
อย่างน้อย 1 รายการ - ชั้นเรียนจะกําหนดเครื่องมือสร้างรองได้มากกว่า 1 รายการโดยใช้
constructor
แต่สไตล์ Kotlin คือการใช้ฟังก์ชันจากโรงงานแทน
ตัวปรับแต่งระดับการเข้าถึงและคลาสย่อย
- ชั้นเรียนและฟังก์ชันทั้งหมดใน Kotlin จะมีค่าเริ่มต้นเป็น
public
แต่คุณจะใช้ตัวแก้ไขเพื่อเปลี่ยนระดับการเข้าถึงเป็นinternal
,private
หรือprotected
ได้ - หากต้องการสร้างคลาสย่อย จะต้องทําเครื่องหมายชั้นเรียนระดับบนสุดว่า
open
- หากต้องการลบล้างเมธอดและพร็อพเพอร์ตี้ในคลาสย่อย วิธีการและพร็อพเพอร์ตี้จะต้องมีการทําเครื่องหมาย
open
ในชั้นเรียนระดับบนสุด - คลาสที่ปิดบังหน้าเว็บจริงอาจอยู่ในคลาสย่อยได้เฉพาะในไฟล์ที่กําหนดไว้เท่านั้น สร้างชั้นเรียนที่ปิดบังหน้าเว็บจริงด้วยการประกาศ
sealed
นําหน้า
คลาสข้อมูล ซิงเกิล และ Enum
- สร้างคลาสข้อมูลโดยนําหน้าการประกาศด้วย
data
- การทําลายเป็นคําอธิบายสั้นๆ สําหรับกําหนดคุณสมบัติของออบเจ็กต์
data
ให้กับตัวแปรต่างๆ - สร้างชั้นเรียนเดี่ยวโดยใช้
object
แทนclass
- กําหนด enum โดยใช้
enum class
ชั้นเรียน อินเทอร์เฟซ และการมอบสิทธิ์
- ชั้นเรียนนามธรรมและอินเทอร์เฟซเป็นการแชร์พฤติกรรมทั่วไประหว่างชั้นเรียน 2 วิธี
- คลาสนามธรรมจะกําหนดพร็อพเพอร์ตี้และพฤติกรรม แต่ออกจากการใช้งานในคลาสย่อย
- อินเทอร์เฟซจะกําหนดลักษณะการทํางาน และอาจจัดเตรียมการใช้งานเริ่มต้นให้กับพฤติกรรมบางส่วนหรือทั้งหมด
- เมื่อใช้อินเทอร์เฟซในการเขียนชั้นเรียน ระบบจะขยายฟังก์ชันการทํางานของคลาสตามอินสแตนซ์ของชั้นเรียนที่มี
- การมอบสิทธิ์อินเทอร์เฟซใช้องค์ประกอบแต่ยังมอบสิทธิ์การติดตั้งใช้งานคลาสอินเทอร์เฟซด้วย
- การจัดองค์ประกอบเป็นวิธีที่มีประสิทธิภาพในการเพิ่มฟังก์ชันในชั้นเรียนโดยใช้การมอบสิทธิ์ในอินเทอร์เฟซ แต่ในการเรียบเรียงโดยทั่วไป ขอแนะนําให้ใช้คลาสแบบนามธรรมที่สืบทอดมาจะเหมาะกับบางปัญหามากกว่า
เอกสารประกอบเกี่ยวกับ Kotlin
หากต้องการข้อมูลเพิ่มเติมเกี่ยวกับหัวข้อใดก็ตามในหลักสูตรนี้หรือคุณติดค้าง https://kotlinlang.org คือจุดเริ่มต้นที่ดีที่สุด
- คลาสและการสืบทอด
- เครื่องมือสร้าง
- ฟังก์ชันจากโรงงาน
- พร็อพเพอร์ตี้และช่อง
- ตัวแก้ไขระดับการเข้าถึง
- ชั้นเรียนนามธรรม
- อินเทอร์เฟซ
- การมอบสิทธิ์
- คลาสข้อมูล
- ความเท่าเทียม
- การทําลาย
- การประกาศออบเจ็กต์
- จํานวนชั้นเรียน
- ชั้นเรียนที่ปิดบังหน้าเว็บจริง
- การจัดการข้อผิดพลาดที่ไม่บังคับโดยใช้ชั้นเรียนที่ปิดด้วย Kotlin
บทแนะนําเกี่ยวกับ Kotlin
เว็บไซต์ https://try.kotlinlang.org มีบทแนะนําที่ครอบคลุมชื่อ Kotlin Koans ซึ่งเป็นล่ามบนเว็บ และชุดเอกสารอ้างอิงที่สมบูรณ์พร้อมตัวอย่าง
หลักสูตร Udacity
ดูหลักสูตร Udacity เกี่ยวกับหัวข้อนี้ที่หัวข้อ Kotlin Bootcamp สําหรับโปรแกรมเมอร์
IntelliJ IDEA
ดูเอกสารสําหรับ IntelliJ IDEA ได้ในเว็บไซต์ JetBrains
ส่วนนี้จะอธิบายการบ้านและรายงานสําหรับนักเรียนที่ทํางานผ่าน Codelab นี้ซึ่งเป็นส่วนหนึ่งของหลักสูตรที่นําโดยผู้สอน สิ่งที่ผู้สอนต้องทํามีดังนี้
- มอบหมายการบ้านหากจําเป็น
- สื่อสารกับนักเรียนเกี่ยวกับวิธีส่งงานทําการบ้าน
- ตัดเกรดการบ้าน
ผู้สอนจะใช้คําแนะนําเหล่านี้เท่าใดก็ได้หรือตามที่ต้องการก็ได้ และสามารถกําหนดให้การบ้านอื่นๆ ที่ตนคิดว่าเหมาะสมได้
หากคุณใช้ Codelab ด้วยตัวเอง ก็ให้ใช้การบ้านเพื่อทดสอบความรู้ของคุณได้
ตอบคําถามเหล่านี้
คำถามที่ 1
ชั้นเรียนจะมีวิธีการพิเศษที่ใช้เป็นพิมพ์เขียวสําหรับสร้างออบเจ็กต์ของชั้นเรียนนั้น วิธีการเรียกว่าอะไร
▢ เครื่องมือสร้าง
▢ ผู้ฝึกสอน
▢ เครื่องมือสร้าง
▢ พิมพ์เขียว
คำถามที่ 2
ข้อความใดเกี่ยวกับอินเทอร์เฟซและชั้นเรียนนามธรรมต่อไปนี้ไม่ถูกต้อง
▢ คลาสนามธรรมมีเครื่องมือสร้างได้
▢ อินเทอร์เฟซต้องไม่มีเครื่องมือสร้าง
สร้างอินสแตนซ์อินเทอร์เฟซและชั้นเรียนนามธรรมโดยตรงได้
▢ พร็อพเพอร์ตี้นามธรรมต้องใช้โดยคลาสย่อยของนามธรรม
คำถามที่ 3
ข้อใดต่อไปนี้ไม่ใช่ตัวปรับแต่งระดับการเข้าถึง Kotlin สําหรับพร็อพเพอร์ตี้ เมธอด ฯลฯ
▢ internal
▢ nosubclass
▢ protected
▢ private
คำถามที่ 4
พิจารณาคลาสข้อมูลนี้:data class Fish(val name: String, val species:String, val colors:String)
ข้อใดต่อไปนี้ไม่ใช่โค้ดที่ถูกต้องสําหรับการสร้างและทําลายออบเจ็กต์ Fish
▢ val (name1, species1, colors1) = Fish("Pat", "Plecostomus", "gold")
▢ val (name2, _, colors2) = Fish("Bitey", "shark", "gray")
▢ val (name3, species3, _) = Fish("Amy", "angelfish", "blue and black stripes")
▢ val (name4, species4, colors4) = Fish("Harry", "halibut")
คำถามที่ 5
สมมติว่าคุณเป็นเจ้าของสวนสัตว์ที่มีสัตว์นานาชนิดที่ต้องดูแลทั้งหมด ข้อใดต่อไปนี้ไม่ใช่ส่วนหนึ่งของการใช้เคอร์เซอร์ข้อความ
▢ interface
สําหรับอาหารประเภทต่างๆ ที่สัตว์กิน
▢ คลาส abstract Caretaker
ซึ่งคุณสามารถสร้างผู้ดูแลได้หลายประเภท
▢ interface
เพื่อให้น้ําสะอาดแก่สัตว์
▢ คลาส data
สําหรับรายการในกําหนดการให้อาหาร
ดําเนินการต่อในบทเรียนถัดไป:
ดูภาพรวมของหลักสูตร รวมถึงลิงก์ไปยัง Codelab อื่นๆ ได้ที่ "Kotlin Bootcamp สําหรับโปรแกรมเมอร์: ยินดีต้อนรับสู่หลักสูตร"