SOLID - Part 4: Nguyên lý I - Interface Segregation Principle (ISP)

1. Đặt vấn đề: 

Trong OOP,  Interface là một khái niệm chung, với Swift thì Protocol là khái niệm đại diện cho Interface. Cho nên khi nói từ Protocol cũng như đang nói Interface. 

Về vấn đề protocol, các bạn có để ý phần DataSource và Delegate của UITableView cũng là như nhau đúng không ? Tại sao không gộp chúng lại thành 1 protocol để dùng cho khoẻ ?

2. Interface Segregation Principle

a. Nguyên tắc và nguyên nhân sử dụng

Clients should not be forced to depend upon interfaces that they do not use

Các clients (class/ module) khi implement các interface không nên bị ràng buộc phải tuân thủ hết tất cả những thứ mà clients không sử dụng. Tức là tránh tình trạng override func nhưng rồi để trống và complier phải tốn thời gian compile những method useless đó. 

b. Áp dụng với Fat Interface cho Protocol

Mình sẽ có ví dụ đơn giản ở phần này, ta có 1 protocol với 3 chức năng. Trong khi class ta chỉ cần có 1 thì rõ ràng hai chức năng kia bị dư thừa. 

Cách fix thì chia nhỏ ra thành 3 interface rồi dùng chức năng nào thì conform chức năng ấy. Cái này khá dễ hình dung nên mình chỉ nói sơ qua.

c. Áp dụng với Fat Interface cho Class

Giả sử bạn có 1 class sau: 

class Video {
    var title: String = "Football"
    var description: String = "Football Match"
    var author: String = "Duy Bui"
    var url: String = "https://duybui297.com/video"
    var duration: Int = 60
    var created: Date = Date()
    var update: Date = Date()
}

Bây giờ ta giả sử có 1 hàm gọi video player:

func play(video: Video) {
    // load the player UI
    // load the content at video.url
    // add video.title to the player UI title
    // update the player scrubber with video.duration
}

Rõ ràng ta chỉ cần vài properties trong khi video có cả đống properties, có vẻ dư thừa. Ta khắc phục bằng cách tạo protocol cho nó như sau: 

Hơn nữa, cách tiếp cận này cũng useful cho việc unit test. Ta sẽ tạo một class nhỏ mà implements protocol Playable 

class StubPlayable: Playable {
    private(set) var isTitleRead = false
 
    var title: String {
        self.isTitleRead = true
        return "My Video"
    }
    var duration = 60
    var url: String = "https://duybui297.com/video"
}
 
func test_Play_IsUrlRead() {
    let stub = StubPlayable()
    play(video: stub)
    XCTAssertTrue(stub.isTitleRead)
}

3. Tổng kết

Ý tưởng của ISP được ứng dụng trong hầu hết các best practice (ví dụ như Delegate & Datasource) vì nó khá đơn giản và dễ hiểu. Và một điều may mắn là trong Swift có Optional, giúp cho ta tận dụng nguyên lý này một cái tối đa. Như vậy là mình đã xong phần 4. Tiếp đến là chữ cuối cùng. Chữ D

Bình luận
* Các email sẽ không được công bố trên trang web.
I BUILT MY SITE FOR FREE USING