In this article I’m aiming to describe the Single Responsibility Principle which is first in the list of SOLID principles. This is very important to understand this if you are looking to create a clean and maintainable project. In order to create Unit tests its important for follow the SRP while you Create the classes.
You can find a detail introduction to SOLID principle in the following article: https://www.scaledrone.com/blog/solid-principles-for-becoming-a-better-ios-swift-developer/
I want to focus on implementing the Single Responsibility principle.
Lets look into the following example:
class EmployeeDatasource {
func getEmployees(completion: @escaping ([SomeEmployees]) -> Void) {
// 1. Create request
let url = URL(string: "SomeEmployee/URL")!
let request = URLRequest(url: url)
// 2. Fetching data
let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in
// 3. Parsing data
guard let data = data,
let employees = try? JSONDecoder().decode([SomeEmployees].self, from: data) else {
completion([])
return
}
completion(employees)
}
dataTask.resume()
}
}
This is a data fetching service that fetches some Employees details from a Url. At the moment EmployeeDatasource class is responsible for three tasks :
1. Creating a request
2. Fetching data
3. Parsing data
This one class has three different responsibility. Which makes the whole class difficult to test and it violates the Single responsibility principle.
Lets try to break it down:
URL builder:
class EmployeesURLBuilder {
private let hostName: String
init(hostName: String) {
self.hostName = hostName
}
func getEmployees() -> URLRequest {
let url = URL(string: "\(hostName)SomeEmployees/URL")!
let request = URLRequest(url: url)
return request
}
}
Employee Parser:
struct SomeEmployees: Codable {
let id: Int
let title: String
let position: String
}
class EmployeesParser {
private let decoder: JSONDecoder
init(decoder: JSONDecoder) {
self.decoder = decoder
}
func parse(data: Data) -> [SomeEmployees] {
return (try? decoder.decode([SomeEmployees].self, from: data)) ?? []
}
}
Let see how the datasource class looks like now:
class EmployeesDatasource {
private let requestBuilder: EmployeesURLBuilder
private let parser: EmployeesParser
init(requestBuilder: EmployeesURLBuilder, parser: EmployeesParser) {
self.requestBuilder = requestBuilder
self.parser = parser
}
func getEmployees(completion: @escaping ([SomeEmployees]) -> Void) {
// First responsibility is to Create request
let request = requestBuilder.getEmployees()
// Second responsibility is to Fetch the data
let dataTask = URLSession.shared.dataTask(with: request) { [weak self] (data, response, error) in
// Third responsibility is to Parsing data
guard let self = self,
let data = data else {
completion([])
return
}
completion(self.parser.parse(data: data))
}
dataTask.resume()
}
}
Now if we look here we can see that we have swapped out the code for building the request and parsing the data for our separate classes. Now our example is following the single responsibility principle. We have 3 classes now:
Benefits here are:
Solid Principles — Single Responsibility Principles -2 was originally published in Evangelist Apps Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.