เริ่มต้น Reactive Programming ด้วย Combine Part3: Stream and Operation
ในบทความก่อนหน้านี้ เราได้รู้จักกันไปแล้วว่า Reactive Programming มันเกิดจาก Streams + Operation ในบทความที่เรามาเจาะลึกกันว่า stream และ operation กันให้เห็นภาพชัดมากขึ้น
Stream
จากบทความแรกเราทำความรู้จัก stream กันไปบ้างแล้ว ซึ่ง stream เปรียบกับ สายน้ำของdataต่างๆที่เกิดขึ้น ณ เวลาใดๆ ดังนั้นเรามาดูตัวอย่างต่อไปนี้ที่มันคือ stream กัน
ตัวอย่าง การพิมพ์ keyboard เช่น
[h, e, l, l, o]
เราสามารถบอกว่าค่าตัวอักษร h, e, l, l, o นี้เป็นสตรีมโดย data นี้เกิดขึ้น ณ เวลาใดๆ
// Marble diagram
stream: |---(h)--(e)--(l)--(l)--(o)----------------------------|
time(s): |----|----|----|----|----|----|----|----|----|----|----|
0 1 2 3 4 5 6 7 8 9 10 11
จาก marble diagram มันอธิบายได้ว่า
- ค่า h เกิดขึ้น ณ วินาทีที่ 1
- ค่า e เกิดขึ้น ณ วินาทีที่ 2
- ค่า l เกิดขึ้น ณ วินาทีที่ 3
- ค่า l เกิดขึ้น ณ วินาทีที่ 4
- ค่า 0 เกิดขึ้น ณ วินาทีที่ 5
อีกตัวอย่าง จาก Tiktok event ที่เกิดขึ้นก็เป็นในรูป stream ได้เช่น
[scroll, scroll, love, scroll, favourite]
- Event เหล่านี้เป็น stream ได้มันจะต้องเกิดขึ้นได้มี เวลา ของ event ด้วย
// Marble diagram
stream: |-----(scroll)-(scroll)--(love)--(scroll)-(favourite)--|
time(s): |--------|--------|--------|--------|--------|--------|
0 1 2 3 4 5 6
จาก marble diagram มันอธิบายได้ว่า
- Event scroll เกิดขึ้น ณ วินาทีที่ 1
- Event scroll เกิดขึ้น ณ วินาทีที่ 2
- Event love เกิดขึ้น ณ วินาทีที่ 3
- Event scroll เกิดขึ้น ณ วินาทีที่ 4
- Event favourite เกิดขึ้น ณ วินาทีที่ 5
Operation
อย่างไรก็ตาม เรามีแค่ stream เรายังไม่สามารถกำหนดพฤติกรรมตามที่เราต้องการได้ มันจำเป็นต้องมีการทำอะไรสักอย่างกับ stream เช่น การบวก(+), การบวก(-) หรือที่เรียกว่า operation
การกำหนดพฤติกรรมที่สมบูรณ์ต้องประกอบไปด้วย streams บวกกับ operations จึงจะสมบูรณ์
|---------------------------------| |---------------------------------|
| Stream1 | + | Operation |
|---------------------------------| |---------------------------------|
ตัวอย่าง: 2 stream ที่มาจาก thermometer 2 ตัว กับ operation เพื่อหาค่า average ของอุณหภูมิเฉลี่ยจาก เครื่องวัดทั้ง 2
// Marble diagram
thermometer1: |------(30)----(27)----(26)----(25)---(25)-----(24)-----|
operation: (value1 + value2) / 2
thermometer2: |--------------(27)------------(23)------------(23)-----|
time: |-------|-------|-------|-------|-------|-------|-------|
00:00 00:30 01:00 01:30 02:00 02:30 03:00 03:30
จาก marble diagram มันอธิบายได้ว่า
stream1 ของ thermometer 1 จะมีเปลี่ยน value ทุกๆ ครึ่ง ชั่วโมง
stream2 ของ thermometer 2 จะมีเปลี่ยน value ทุกๆ 1 ชั่วโมง
operation เป็นการคำนวณหาค่าอุณหภูมิเฉลี่ย เมื่อ stream
งั้นเรามามอง ตัวอย่างนี้ในมุมมอง Code
import Combine
// stream1
let thermometer1 = PassthroughSubject<Double, Never>()
// stream2
let thermometer2 = PassthroughSubject<Double, Never>()
let combinedCancellable = Publishers.CombineLatest(thermometer1, thermometer2)
// operation
.map { temperature1, temperature2 in
return (temperature1 + temperature2) / 2
}.sink { averageTemperature in
print("Average Celsius (C): \(averageTemperature)")
}
// Time
// 00:30
thermometer1.send(30)
// 01:00
thermometer1.send(27)
thermometer2.send(27)
// 01:30
thermometer1.send(26)
// 02:00
thermometer1.send(25)
thermometer2.send(23)
// 02:30
thermometer1.send(25)
// 03:00
thermometer1.send(24)
thermometer2.send(23)
Output
// Time
01:00 Average Celsius (C): 32.5
01:30 Average Celsius (C): 32.5
02:00 Average Celsius (C): 32.5
02:00 Average Celsius (C): 32.5
02:30 Average Celsius (C): 32.5
03:00 Average Celsius (C): 32.5
03:00 Average Celsius (C): 32.5
Program ended with exit code: 0
สรุปจากตัวอย่าง เราได้ทำการกำหนดพฤติกรรมใว้สำหรับรอการไหลเข้ามาของ data และเมื่อ run มาถึง thermometer1.send(30) เป็นการจำลองว่ามีการเกิด data ณ เวลา 1:00 data ก็จะไหลเข้าไปและเกิดพฤติกรรมตามที่กำหนด
อาจจะมีคำถามเกี่ยวกับ CombineLatest จริงๆมันก็คือ Functional Reactive Programming อันหนึ่ง ซึ่งเคยได้กล่าวมาในแบบแรก แต่บทถัดไปเราจะมาลงลึกกับหัวข้อนี้ครับ
Next part4: Reactive Programming ด้วย Combine Part4: Publisher, Subscriber and Cancellable