Anytime you have some logic in a class which checks 2 or more of its properties to represent a state or condition of some sort, consider wrapping that into an enum.
For example:
class Payment {
var isFree: Bool
var price: Int?
var currency: String?
init() { //... }
function send() {
if isFree {
//do something
} else {
if let price = price, let currency = currency {
//do something with price + currency
} else {
//handle this somehow
}
}
}
}
Change it to:
class Payment {
enum Type {
case free
case paid(price: Int, currency: String)
}
var type: Type
init() { //... }
function send() {
switch type {
case .free:
//do something
case .paid(let price, let currency):
//do something with price + currency
}
}
}
The code ends up clearer — being explicit that it's handling 2 states, free and paid — and it's less likely to introduce bugs because the code paths are easier to follow and if you need to do something that depends on the type, the compiler will force you to handle all the possible states (free and paid).
The resulting code can sometimes end up being longer, but it's a worthy trade-off.
.
.