Như những gì tôi đã nói ở trong các buổi hội nghị gần đây, cuốn sách Refactoring to Patterns luôn được nhắc đến trong các buổi nói chuyện ưa thích của tôi. Và cuối cùng thì tôi cũng đã có thời gian để đọc nó (sau một đợt WWDC bận rộn), và tôi muốn tổng hợp lại những gì tôi đọc được tại đây để tiện tham khảo cho tương lai. Trong quá trình đọc thì tôi cũng ngộ ra được một cách ghi nhớ rất tốt, đó là dịch từ ngôn ngữ Java sang Swift.
Hôm nay chúng ta sẽ nói về pattern đầu tiên, đó là Creation Method.
Trước khi refactor
Giả dụ bạn có một model, có tên gọi là Loan( các khoản cho vay), nó có rất nhiều thuộc tính và các hàm initializer khác nhau. Ở trong trường hợp này mỗi hàm initializer được khai báo với một mục đích khác nhau - tương ứng với từng loại hình cho vay:
struct Loan {
let commitment: NSDecimalNumber
let riskRating: Float
let maturity: Int
let expiry: NSDate?
let capitalStrategy: String?
let outstanding: NSDecimalNumber?
init(commitment: NSDecimalNumber, riskRating: Float, maturity: Int, expiry: NSDate?, capitalStrategy: String?, outstanding: NSDecimalNumber?) {
self.commitment = commitment
self.riskRating = riskRating
self.maturity = maturity
self.expiry = expiry
self.capitalStrategy = capitalStrategy
self.outstanding = outstanding
}
init(commitment: NSDecimalNumber, riskRating: Float, maturity: Int) {
self.init(commitment: commitment, riskRating: riskRating, maturity: maturity, expiry: nil, capitalStrategy: nil, outstanding: nil)
}
init(commitment: NSDecimalNumber, riskRating: Float, maturity: Int, expiry: NSDate) {
self.init(commitment: commitment, riskRating: riskRating, maturity: maturity, expiry: expiry, capitalStrategy: nil, outstanding: nil)
}
init(commitment: NSDecimalNumber, outstanding: NSDecimalNumber, riskRating: Float, maturity: Int, expiry: NSDate) {
self.init(commitment: commitment, riskRating: riskRating, maturity: maturity, expiry: expiry, capitalStrategy: nil, outstanding: outstanding)
}
init(capitalStrategy: String, commitment: NSDecimalNumber, riskRating: Float, maturity: Int, expiry: NSDate) {
self.init(commitment: commitment, riskRating: riskRating, maturity: maturity, expiry: expiry, capitalStrategy: capitalStrategy, outstanding: nil)
}
init(capitalStrategy: String, commitment: NSDecimalNumber, outstanding: NSDecimalNumber, riskRating: Float, maturity: Int, expiry: NSDate) {
self.init(commitment: commitment, riskRating: riskRating, maturity: maturity, expiry: expiry, capitalStrategy: capitalStrategy, outstanding: outstanding)
}
}
Nhìn vào trong đoạn code trên, bạn sẽ khá hoang mang không biết phải sử dụng intializer nào. Dĩ nhiên là đối với người mới thì sẽ khá lẫn lộn vì họ không nắm được rõ về nghiệp vụ này, vì vậy sẽ dẫn đến việc sử dụng nhầm intializer. Do đó chúng ta cần phải refactor lại.
Sau khi refactor
Đoạn code dưới đây được gọi là refactor theo Creation Method
struct Loan {
let commitment: NSDecimalNumber
let riskRating: Float
let maturity: Int
let expiry: NSDate?
let capitalStrategy: String?
let outstanding: NSDecimalNumber?
// the original initializer can now be private
private init(commitment: NSDecimalNumber, riskRating: Float, maturity: Int, expiry: NSDate?, capitalStrategy: String?, outstanding: NSDecimalNumber?) {
self.commitment = commitment
self.riskRating = riskRating
self.maturity = maturity
self.expiry = expiry
self.capitalStrategy = capitalStrategy
self.outstanding = outstanding
}
static func createTermLoan(commitment: NSDecimalNumber, riskRating: Float, maturity: Int) -> Loan {
return Loan(commitment: commitment, riskRating: riskRating, maturity: maturity, expiry: nil, capitalStrategy: nil, outstanding: nil)
}
static func createTermLoan(capitalStrategy: String, commitment: NSDecimalNumber, outstanding: NSDecimalNumber, riskRating: Float, maturity: Int, expiry: NSDate) -> Loan {
return Loan(commitment: commitment, riskRating: riskRating, maturity: maturity, expiry: expiry, capitalStrategy: capitalStrategy, outstanding: outstanding)
}
static func createRevolverLoan(commitment: NSDecimalNumber, outstanding: NSDecimalNumber, riskRating: Float, maturity: Int, expiry: NSDate) -> Loan {
return Loan(commitment: commitment, riskRating: riskRating, maturity: maturity, expiry: expiry, capitalStrategy: nil, outstanding: outstanding)
}
static func createRevolverLoan(capitalStrategy: String, commitment: NSDecimalNumber, riskRating: Float, maturity: Int, expiry: NSDate) -> Loan {
return Loan(commitment: commitment, riskRating: riskRating, maturity: maturity, expiry: expiry, capitalStrategy: capitalStrategy, outstanding: nil)
}
static func createRCTL(commitment: NSDecimalNumber, riskRating: Float, maturity: Int, expiry: NSDate) -> Loan {
return Loan(commitment: commitment, riskRating: riskRating, maturity: maturity, expiry: expiry, capitalStrategy: nil, outstanding: nil)
}
}
Sau khi refactor xong thì nhìn code trở nên sáng sủa hơn hẳn, và quan trọng nhất là phân loại rõ được các hàm initializer. Bên cạnh pattern này thì còn có nhiều kiểu khởi tạo khác trong Swift tùy thuộc vào các trường hợp (ví dụ: enums), do vậy tôi sẽ sử dụng pattern này trong trường hợp muốn code của mình trở nên dễ đọc và tường minh hơn.
Bình luận