[Swift] Protocol Oriented Programming

Mở đầu

Tại WWDC 2015, Apple đã release Swift 2 với rất nhiều tính năng mới hỗ trợ cho việc lập trình với Swift. Một trong những tính năng đó là Protocol Extensions hỗ trợ việc extend một protocol. Điều đó cũng đồng nghĩa với việc Protocol bây giờ thực sự là một thứ rất mạnh mẽ và có thể thay đổi cách viết code của bạn. Đó cũng là bước đánh dấu Protocol Oriented Programming ra đời

Để hiểu hơn về Protocol Oriented Programming, chúng ta sẽ tìm hiểu qua về Protocol, thành phần cơ bản của Protocol Oriented Programming

Protocol là gì

Một Protocol có thể được hiểu là một bản thiết kế để định nghĩa một tập hợp các properties và các method. Một protocol có thể được adopt bởi 1 class, 1 struct hoặc 1 enum. Class/ struct/ enum khi "conform" protocol sẽ phải cung cấp cho các property và method những giá trị và sự thực thi tương ứng cho protocol đó.

Ví dụ về 1 protocol


protocol SomeProtocol {
    // protocol definition goes here
    var mustBeSettable: Int { get set }
    var doesNotNeedToBeSettable: Int { get }
}

protocol Bird {
    var canFly: Bool
    func fly()
}

Protocol Oriented Programming

Protocol-oriented programming là một mô hình OOP nhưng nó ưu tiên việc sử dụng các protocol và struct thay vì sử dụng các class

Để hiểu rõ hơn về Protocol oriented programming, chúng ta sẽ cùng làm 1 ví dụ nhỏ

Đầu tiên, thay vì bắt đầu bằng 1 class như OOP, chúng ta sẽ bắt đầu với 1 protocol

protocol Developer {
    var programmingLanguage : [String] { get }
    var handsome : Bool { get }
    var name : String { set get }
}

protocol Handsome {
    var handsomeLevel : Int { get set }
}

Tạo 1 struct để conform các protocol trên

enum ProgrammingLanguage: String {
    case Swift = "Swift"
    case ObjectiveC = "Objective C"
    case Java = "Java"
}

struct AndroidDev: Developer {
    var programmingLanguage: [String] {
        return [ProgrammingLanguage.Java.rawValue]
    }
    var handsome: Bool {
        return false
    }
    var name: String
}

struct iOSDev: Developer, Handsome {
    var programmingLanguage: [String] {
        return [ProgrammingLanguage.Swift.rawValue, ProgrammingLanguage.ObjectiveC.rawValue]
    }
    var handsomeLevel: Int
    var name: String
}

Với struct AndroidDev, chúng ta k có gì để nói thêm cả, AdroidDev conform protocol Developer, nên nó phải implementation tất cả các biến của protocol Developer

Tuy nhiên với struct iOSDev, chúng ta sẽ có suy nghĩ, nếu đã kế thừa protocol Handsome thì tất nhiên giá trị handsome phải bằng true rồi, vậy làm sao để xét mặc định cho giá trị các struct kế thừa protocol Handsome ???

Với protocol extensions, chúng ta có thể dễ dàng xét các giá trị mặc định cho protocol một cách dễ dàng

extension Developer where Self: Handsome {
    var handsome: Bool {
        return true
    }
}

với extension trên, mỗi struct conform protocol Developer vừa conform protocol Handsome sẽ có giá trị mặc định của biến handsome = true, chúng ta có thể bỏ phần conform biees handsome trong struct đi

struct iOSDev: Developer, Handsome {
    var programmingLanguage: [String] {
        return [ProgrammingLanguage.Swift.rawValue, ProgrammingLanguage.ObjectiveC.rawValue]
    }
    var handsomeLevel: Int {
        return 10000
    }
}

Extending Protocol

Có lẽ tính năng hữu ích nhất của protocol extension chính là giúp chúng ta có thể extending các external protocols bao gồm những protocol được định nghĩa trong Swift standard library hoặc trong 1 third party framework.

Chúng ta sẽ cùng sử dụng nó với ví dụ trên

extension CollectionType where Generator.Element: Developer, Generator.Element :Handsome {
    func theMostHandsomer() -> String {
        var mostHandsomer = self.first!
        for handsomer in self {
            if handsomer.handsomeLevel > mostHandsomer.handsomeLevel {
                mostHandsomer = handsomer
            }
        }
        return mostHandsomer.name
    }
}

let quocnb = iOSDev(handsomeLevel: 10000, name: "Quoc Nguyen")
let hoangls = iOSDev(handsomeLevel: 1, name: "Hihi")
print([quocnb, hoangls].theMostHandsomer()) // Print: Quoc Nguyen

Ở đây, với mảng các struct conform cả protocol Developer và protocol Handsome, chúng ta sẽ viết thêm 1 function để tìm ra theMostHansomer. Với tất cả các mảng như thế, chúng ta có thể gọi hàm .theMostHandsomer để tìm ra kết quả

Ưu điểm của việc sử dụng protocol thay vì sử dụng các class

Trên đây, chúng ta đã trình bày việc sử dụng Protocol oriented programming bằng việc sử dụng các protocol đơn giản và extend chúng với protocol extensions. Protocol extensions không chỉ extend các protocol mà còn có thể sử dụng để cung cấp các default variable, default method cho các protocol.

Việc sử dụng protocol với Swift sẽ có những ưu điểm so với việc sử dụng class :

  • Protocol có thể được adopt bởi class, struct và enum. Base class bị giới hạn chỉ trong phạm vi class. Chỉ có class mới kế thừa được từ class khác
  • Trong khi một class chỉ có thể được thừa kế từ 1 class cha thì một class, struct, enum có thể adopt được nhiều protocol. Khi một class phải thừa kế 1 property, hoặc 1 method default mà nó k dùng tới từ 1 class cha thì với protocol, chúng ta có thể chia nhỏ các method, các property ra để phù hợp với nhiều class.

=> Việc sử dụng Protocol giúp chúng ta có thể xử lý công việc một cách linh hoạt hơn với nhiều lựa chọn hơn.

Kết

Trên đây tôi đã giới thiệu qua về Protocol Oriented Programming với ngôn ngữ Swift. Hi vọng nó sẽ giúp các bạn có cái nhìn gần gũi hơn với cách viết mới này và vận dụng nó 1 cách thành thạo nhất