Protocols

Swift có một tính năng thú vị đó là protocol. Protocol là một cách nhìn khác của việc kế thừa class. Trong lập trình hướng đối tượng, bạn khai báo class mô tả đối tượng và tính năng của chúng, song song với những thuộc tính. Sau đó, bạn subclass những class đó, kế thừa lại những thuộc tính và tính năng của class cha, đồng thời tạo thêm nhiều tính năng và thuộc tính khác, và class con lại có class cháu, class chắt..vv. 

class Animal {
    func makeSound() {
        print("Implement me!")
    }
    
    func move() {
        print("Implement me!")
    }
}
 
class Dog: Animal {
    override func makeSound() {
        print("Woof.")
    }
    
    override func move() {
        print("walk around like a dog")
    }
    
    func bite() {
        print("bite")
    }
}
 
class Cat: Animal {
    override func makeSound() {
        print("Meow.")
    }
    
    override func move() {
        print("walk around like a cat")
    }
    
    func scratch() {
        print("scratch")
    }
}

Ví dụ trên mô tả một "gia phả" class, với class gốc là Animal. Class Dog subclass từ Animal và kế thừa mọi tính năng của nó, đồng thời có thêm một function bite() riêng biệt, class Cat cũng vậy với function scratch().

Bạn có thấy vấn đề gì ở trong ví dụ trên khong?. Nhìn qua thì có vẻ là không, nhưng thực tế, có rất nhiều thứ cần phải cải thiện. Ví dụ như nếu một ai đó subclass Animal nhưng quên override function makeSound() thì sao?

class Tiger: Animal {
    func eat() {
        print("Eat like a tiger")
    }
}
 
let animal: Animal = Tiger()
animal.makeSound()   // Implement me!
animal.move()        // Implement me!
Tham khảo các khóa học lập trình online, onlab, và thực tập lập trình tại TechMaster

Đây chỉ là một ví dụ đơn giản, nhưng tưởng tượng điều gì sẽ xảy ra nếu Animal có hàng tá những function mà cần phải override?

Ở Objective C, những tình huống trên gọi là abstract base class. Abstract base class giống như Animal nhưng thực tế chúng không cung cấp nhiều tính năng. Chúng tạo ra rất nhiều thứ cần phải override, hay nói cách khác là chúng ta phải override những thứ mà thừa thãi so với mục đích sử dụng của chúng ta. Và vì lý do này, abstract base classes được định nghĩa là abstract, vì lập trình viên chỉ được làm việc với những subclass, không phải class gốc ban đầu. Ví dụ, UIViewController là subclass của UIResponder, nhưng ko phải lập trình viên nào cũng làm việc với UIResponder thường xuyên.

Trong Swift, không có khái niệm abstract class. Tuy nhiên, Swift (và cả Objective-C) đều có cách tốt hơn, đó là protocol. Và ở trong Swift thì protocol mạnh mẽ hơn. Ví dụ chúng ta có thể khởi tạo Animal như một protocol như sau:

 

protocol Animal {
    func makeSound()
    func move()
}
 
struct Dog: Animal {
    func makeSound() {
        print("Woof.")
    }
    
    func move() {
        print("walk around like a dog")
    }
    
    func bite() {
        print("bite")
    }
}
 
struct Cat: Animal {
    func makeSound() {
        print("Meow.")
    }
    
    func move() {
        print("walk around like a cat")
    }
    
    func scratch() {
        print("scratch")
    }
}

Điều khác biệt ở đây là gì, chúng ta vẫn có Dog và Cat và đều có những tính năng tương tự mà chúng kế thừa được. Nhưng, tại lúc này, cả 2 con vật đều tuân thủ theo một protocol. Như bạn đã thấy, thì một class định nghĩa cái gì là object, nhưng protocol định nghĩa object làm cái gì. 

let animal: Animal = Dog()
animal.makeSound()
animal.move()

Cả Cat và Dog đều tuân thủ protocol Animal. Và đều có thể thực thi các method makeSound và move. Khi tuân thủ theo một protocol, trình biên dịch sẽ buộc những class hay struct phải thực thi những method có trong protocol đó.

Trình biên dịch sẽ báo lỗi để đảm bảo rằng bạn phải thực thi đầy đủ những method có trong protocol.

Chúng ta sẽ tìm hiểu sâu hơn về protocol ở một bài viết chuyên sâu hơn, có liên quan đến tư duy lập trình hướng giao thức, Protocol Oriented Programming (POP).  Tuy nhiên, chúng ta không bắt buộc phải chuyển sang hẳn protocol, bạn vẫn phải sử dụng cả 2 phương pháp. Mọi thứ đều có điểm hay và điểm dở của chúng.