POP-protocol-oriented programming

POP-protocol-oriented programming

What is protocol-oriented programming?

Protocol-oriented = Protocol + Extension + Inheritance Dividing functions through protocols and extensions reduces the coupling between modules and enhances the scalability of the code. iOSOne of the shortcomings is multiple inheritance, and the agreement can just solve the problem of multiple inheritance. The Swiftstructure has become more powerful in China, not only can define properties, but also define methods, and multiple inheritance protocols, which is OCnot provided.

Let's go through an example to get a feel for the charm of agreement-oriented.

Network request encapsulation

1. Agreement statement-base

protocol HBRequest {
    var host: String {get}
    var path: String {get}
    var method: HBHTTPMethod {get}
    var parameter: [String : Any] {get}
    
    associatedtype Response
    func parse(data:Data) -> Response?
}
 

Declare a protocol, define the attributes related to the request, and define the modeling method. Note that the model here does not know the specific type of model to be transferred, so an associated attribute is declared here, which is generic to the outside model. This is modeldetermined by the configuration requested by the outside world.

The protocol attribute should be assigned in the specific business, and the request method is used by every business module, so the request method should be treated as a public method.

2. Implementation request method

extension HBRequest {
    func send(handler: @escaping(Response?) -> Void) {
        // -   - model
        let url = URL(string: host.appending(path))!
        var request = URLRequest(url: url)
        request.httpMethod = method.rawValue
        let task = URLSession.shared.dataTask(with: request){
            (data,reponse,error) in
            if let data = data, let resp = self.parse(data: data){
                DispatchQueue.main.async {
                    handler(resp)
                }
            }else{
                DispatchQueue.main.async {
                    handler(nil)
                }
            }
        }
        task.resume()
    }
}
 

The extended protocol implements the protocol method, puts the network request module in the method, and exposes the closure to facilitate the transfer of internal and external values. Pass data out through the main thread.

The modeled self.parsemethod is called here to return the model to the outside world. Why is it called without implementation here? This is different from our usual sequential processing, where the modeling method is implemented in the request configuration model. Some people will definitely wonder why not just return to datathe outside world for processing? Imagine if the deal closed by the package to external, general request is initiated in the business layer, the business layer, or that Controllerit will not only have to deal with a view to load data processing, and this time the division of labor on the confusion. MVC MVVMIt runs counter to the architectural thinking we want . Therefore, it is most reasonable to return the model to the business layer, and the data processing will be handled by the modellayer.

The above-declared protocol and extensions to the protocol can be used as the basic class of the request. Under the same file, the business layer initiates a request to directly call this method, of course, through the successor of the protocol, that is model, the request configuration structure in the specific file Body to call.

3. Model construction and serialization-model

The structure is the best carrier for data classification, so the model chooses the structure to manage our attributes. The implementation is as follows:

struct HBPerson {
    let name: String
    let headimg: String
    let description: String
    
    //
    init?(data:Data) {
        guard let obj = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String:Any] else {
            return nil
        }
        let data = obj["data"] as! [String:String]
        self.name = data["name"]!
        self.headimg = data["headimg"]!
        self.description = data["description"]!
    }
}
 
  • Set model properties
  • Passed in during initialization datafor data analysis

In addition to building the model, you also need to configure network request parameters:

struct HBUserInfoRequest : HBRequest{
    var host: String = "http://onapp.yahibo.top/public/?s=api/"
    var path: String = "test/info"
    var method: HBHTTPMethod = .GET
    var parameter: [String : Any] = [:]
    
    typealias Response = HBPerson
    
    //
    func parse(data: Data) -> HBPerson? {
        return HBPerson(data: data)
    }
}
 
  • HBUserInfoRequestInherited from the basic protocol, configure the request parameters
  • The serialization method that implements the basic protocol, which HBRequestis called in the extension
  • The method modelto return the processed data that is the object to HBRequestin send, so that the specific modelobject can be obtained in the business layer

The above two structures can be grouped into one modelclass and implemented in the same file, which is equivalent to OCone modelclass.

4. Initiate a request-controller

let request = HBLoginRequest()
request.send {[weak self] (person) in
    print(person?.headimg as Any)
    self?.imageview.kf.setImage(with: URL.init(string: ""))
    self?.nameLabel.text = person?.name
    self?.descriptionLabel.text = person?.description
}
 

Create the request object directly and initiate the request. Perfect. At this time, the functions of each layer have been divided, namely:

Request base layer (base) + data layer (model) + business layer (controller)

The above is an example of simple network request encapsulation, which connects the model layer and the business layer well through the protocol. Of course, in the previous RxSwiftstudy, we can feel the charm of the agreement more, and the coupling of the functional modules is lifted through the agreement.