Handle Application Permissions Using Template Method.

Screen Shot 2021-08-11 at 1.56.29 AM.png

In our daily work as software developers, we face problems that have specific characteristics that make our source code more complex, hard to maintain ... etc., here come the Design Patterns.

A design pattern is a general repeatable solution to a commonly occurring problem in software design. A design pattern isn't a finished design that can be transformed directly into code. It is a description or template for how to solve a problem that can be used in many different situations.

today we're going to talk about Template Method design pattern, template method is is a behavioral design pattern that defines the skeleton of an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing its structure.

When to use Template Method ?

  • Let subclasses implement varying behavior (through method overriding)
  • Avoid duplication in the code, the general workflow structure is implemented once in the abstract class’s algorithm, and necessary variations are implemented in the subclasses.
  • Control at what points subclassing is allowed. As opposed to a simple polymorphic override, where the base method would be entirely rewritten allowing radical change to the workflow, only the specific details of the workflow are allowed to change

via GIPHY

Now It's example time.

Now let's imagine that we're working on an application that will request camera, photo library, microphone, .. etc. permissions from the user. The default scenario for working with permissions is first we check if we're authorized to use user data if we are not authorized we request access for what we want.

Screen Shot 2021-08-11 at 2.33.43 AM.png

so this is our algorithm so instead of repeating it for each case we can use the template method to make it easier and to solve this problem

we create a new file let's call it PermissionService and the following code :

typealias AuthorizationCompletion = (status: Bool, message: String)

class PermissionService: NSObject {
    private var message: String = ""

    func authorize(_ completion: @escaping (AuthorizationCompletion) -> Void) {
        let status = checkStatus()

        guard !status else {
            complete(with: status, completion)
            return
        }

        requestAuthorization { [weak self] status in
            self?.complete(with: status, completion)
        }
    }

    func checkStatus() -> Bool {
        return false
    }

    func requestAuthorization(_ completion: @escaping (Bool) -> Void) {
        completion(false)
    }

    func formMessage(with status: Bool) {
        let messagePrefix = status ? "You have access to " : "You haven't access to "
        let nameOfCurrentPermissionService = String(describing: type(of: self))
        let nameOfBasePermissionService = String(describing: type(of: PermissionService.self))
        let messageSuffix = nameOfCurrentPermissionService.components(separatedBy: nameOfBasePermissionService).first!
        message = messagePrefix + messageSuffix
    }

    private func complete(with status: Bool, _ completion: @escaping (AuthorizationCompletion) -> Void) {
        formMessage(with: status)

        let result = (status: status, message: message)
        completion(result)
    }
}

so as an abstract class it holds the algorithm that will be used in requesting permissions.

now we create CameraPermissionService and add the following lines:

import Foundation
import AVFoundation


class CameraPermissionService: PermissionService {
    override func checkStatus() -> Bool {
        let status = AVCaptureDevice.authorizationStatus(for: .video).rawValue
        return status == AVAuthorizationStatus.authorized.rawValue
    }

    override func requestAuthorization(_ completion: @escaping (Bool) -> Void) {
        AVCaptureDevice.requestAccess(for: .video) { status in
            completion(status)
        }
    }
}

we override the checkStatus function and requestAuthorization function as you can see to use the camera.

then create a new file called PhotoPermissionService and add the following:

import Foundation
import Photos

class PhotoPermissionService: PermissionService {
    override func checkStatus() -> Bool {
        let status = PHPhotoLibrary.authorizationStatus().rawValue
        return status == PHAuthorizationStatus.authorized.rawValue
    }

    override func requestAuthorization(_ completion: @escaping (Bool) -> Void) {
        PHPhotoLibrary.requestAuthorization { status in
            completion(status.rawValue == PHAuthorizationStatus.authorized.rawValue)
        }
    }
}

and you can use any service as the following :

 let cameraPermissionService = CameraPermissionService()
 photoPermissionService.authorize { (_, message) in
      print(message)
 }

Check your console for the result 💻🌟

That’s it hopefully you got it and it was simple and clear for you, if you found this article helpful please leave some claps and share it so everyone can benefit from it too❤️.