Swift’s protocol as a Concrete Type for extension constraint (in Burmese)
Prerequisite
- Basic knowledge of Swift syntax
- Extension in Swift
What I’ll cover
- Modeling similar room packages with protocol
- Create an Array extension
- Hold on, there’s a problem
- The solution
- နိဂုံး
Modeling similar room packages with protocol
Codigo မှာ ကျွန်တော်ပင်တိုင်ကိုင်ရတဲ့ project ကတော့ Resorts World Sentosa ပေါ့။ အဲ့မှာ hotel module ကျတော့ room packages တွေ ပါလာရော။ Room package တွေက data structure similar ဖြစ်ပေမယ့် တစ်ချို့နေရာတွေမှာ ကွဲပြားတာလေးတွေရှိတယ်။ အဲ့တော့ကာ ကျွန်တော်က AnyRoomPackage ဆိုတဲ့ protocol လေးထုတ်ပြီး package တွေကို model လုပ်ကြည့်မယ်။ Code ရေးပြရရင် အောက်ကလို့ပေါ့။
protocol AnyRoomPackage {
var roomId: String { get }
var roomName: String { get }
var priceRate: Double { get }
var selectedRoomCount: Int { get set }
}
Room package အနေနဲ့ genting rewards user (GR) တွေအတွက် package model တစ်ခု non-genting rewards user (Non-GR) တွေအတွက် model တစ်ခု ဆောက်လိုက်ပါမယ်။
struct GRRoomPackage: AnyRoomPackage {
let roomId = UUID().uuidString
let roomName: String
let priceRate: Double
var selectedRoomCount: Int
}
struct NonGRRoomPackage: AnyRoomPackage {
let roomId = UUID().uuidString
let roomName: String
let priceRate: Double
var selectedRoomCount: Int
}
ပြီးရင် room package တွေကို စုထားတဲ့ array တစ်ခုရှိပါမယ်။
let grRooms: [some AnyRoomPackage] = [
GRRoomPackage(roomName: "Deluxe Twin Suites", priceRate: 1020, selectedRoomCount: 1),
GRRoomPackage(roomName: "Equarius Ocean Suite", priceRate: 782, selectedRoomCount: 2),
GRRoomPackage(roomName: "Merlion Suite", priceRate: 942, selectedRoomCount: 1)
]
ဒီနေရာမှာ
some
နဲ့any
ရဲ့ အသုံးပြုပုံကိုမသိသေးရင် ကျွန်တော့်ရဲ့အရင် article ကို ပြန်ဖတ်ပေးပါ။
Create an Array extension
အချိန်တစ်ခုရောက်လာတဲ့အခါ array ထဲက package တွေရဲ့ total price ကို သိချင်လာတာမျိုးရှိတတ်ပါတယ်။ ဒါဆိုရင် Array extension ရေးလိုက်ရင် ဖြစ်ပါတယ်။
extension Array where Element: AnyRoomPackage {
var totalPrice: Double {
var total: Double = 0.0
for room in self {
total += room.priceRate * Double(room.selectedRoomCount)
}
return total
}
}
print(grRooms.totalPrice) // this gonna print 3526.0
အပေါ်က code က အခုအထိတော့အဆင်ပြေနေပါသေးတယ်။
Hold on, there’s a problem
ဒါပေမယ့် အပေါ်က array extension မှာ ပြသနာတစ်ခုရှိပါတယ်။ grRooms
ဆိုတဲ့ array ဟာ GRRoomPackage
type တစ်မျိုးတည်းသာပါတဲ့ homogeneous array ဖြစ်ပါတယ်။ အဲ့လိုမဟုတ်ပဲ GRRoomPackage
ရော NonGRRoomPackage
ကိုပါ array ထဲသိမ်းထားချင်တယ်ဆိုတာမျိုး ရှိလာနိုင်ပါတယ်။ ဘယ်လိုလဲဆိုတော့ အောက်က code လိုမျိုးပေါ့။
let rooms: [any AnyRoomPackage] = [
GRRoomPackage(roomName: "Deluxe Twin Suites", priceRate: 1020, selectedRoomCount: 1),
NonGRRoomPackage(roomName: "Equarius Ocean Suite", priceRate: 882, selectedRoomCount: 2),
GRRoomPackage(roomName: "Merlion Suite", priceRate: 942, selectedRoomCount: 1)
]
ပြီးရင် rooms.totalPrice
လို့ခေါ်လိုက်တဲ့အခါ ကျွန်တော်တို့ရဲ့ array extension ထဲက computed property က accessible မဖြစ်တော့ပါဘူး။ Type 'any AnyRoomPackage' cannot conform to 'AnyRoomPackage’ ဆိုပြီး error တက်သွားပါလိမ့်မယ်။ ဘာကြောင့်လဲဆိုတော့ extension Array where Element: AnyRoomPackage
ဆိုတာက array ရဲ့ element သည် AnyRoomPackage
ကို implement လုပ်တဲ့ concrete type တစ်ခုတည်းကိုသာ သွားပြီး constraint လုပ်လိုက်တာဖြစ်ပါတယ်။
The solution
ကျွန်တော်တို့ရဲ့ အပေါ်က usecase လို AnyRoomPackage
ရဲ့ subclass အကုန်လုံးကိုရောထားတဲ့ heterogeneous array ဆိုရင်တော့ AnyRoomPackage ကို concrete type တစ်ခုအနေနဲ့ constraint လုပ်ရမှာဖြစ်ပါတယ်။ ဘယ်လိုလုပ်ရမလဲဆိုတော့ အောက်က code ကိုကြည့်လိုက်ပါ။ အင်မတန်လွယ်ပါတယ်။
extension Array where Element == AnyRoomPackage {
var totalPrice: Double {
// The same above logic to calculate total price here ...
}
}
Type constraint မှာ ‘:’ အစား ‘==’ ပြောင်းပေးလိုက်တာပါ။ ‘==’ က ဘာကိုပြောတာလဲဆိုတော့ array ရဲ့ element type က AnyRoomPackage type ဖြစ်မယ်ဆိုရင် တစ်နည်းပြောရရင် protocol ကို concrete type တစ်ခုသဖွယ်ပြုမူပြီး constraint လုပ်လိုက်တာဖြစ်ပါတယ်။ ဒါဆိုရင် rooms.totalPrice က ပြန်ရသွားပါလိမ့်မယ်။
print(rooms.totalPrice) // This gonna print 3726.0
နိဂုံး
ဒါဆိုရင်တော့ extension type constraint မှာ ‘:’ နဲ့ ‘==’ ရဲ့ ကွဲပြားခြားနားပုံနဲ့ ဘယ်အချိန်မှာဘာကိုသုံးရမလဲဆိုတာ ကောင်းကောင်းသဘောပေါက်ပြီလို့ယူဆပါတယ်။ ဒီအတိုင်းကြည့်လိုက်ရင်အတူတူလို့ထင်ရပေမယ့် နောက်ကွယ်မှာ သိမ်မွေ့တဲ့ different usecase ရှိနေတာ သတိပြုမှတ်သားစရာပါ။