CODESAMPLE

Policy - Swift

Share on:

The Policy pattern allows you to encapsulate a complex set of business rules into separate, interchangeable policy objects. This promotes flexibility and maintainability by avoiding monolithic conditional logic. Instead of a single class making decisions based on numerous if/else statements, different policies can be applied to a context, each handling a specific aspect of the decision-making process.

This Swift implementation defines a ValidationPolicy protocol with a isValid(for:) method. Concrete policies like LengthPolicy and CharacterPolicy conform to this protocol, each implementing its own validation rule. A Validator class takes an array of ValidationPolicy instances and applies them sequentially to a given string. The use of a protocol and composition aligns with Swift’s emphasis on protocol-oriented programming and avoids tight coupling.

// ValidationPolicy.swift

protocol ValidationPolicy {
    func isValid(for input: String) -> Bool
}

// LengthPolicy.swift
struct LengthPolicy: ValidationPolicy {
    private let minLength: Int
    private let maxLength: Int

    init(minLength: Int, maxLength: Int) {
        self.minLength = minLength
        self.maxLength = maxLength
    }

    func isValid(for input: String) -> Bool {
        return input.count >= minLength && input.count <= maxLength
    }
}

// CharacterPolicy.swift
struct CharacterPolicy: ValidationPolicy {
    private let allowedCharacters: CharacterSet

    init(allowedCharacters: CharacterSet) {
        self.allowedCharacters = allowedCharacters
    }

    func isValid(for input: String) -> Bool {
        return allowedCharacters.isSuperset(of: input.unicodeScalars)
    }
}

// Validator.swift
class Validator {
    private let policies: [ValidationPolicy]

    init(policies: [ValidationPolicy]) {
        self.policies = policies
    }

    func validate(input: String) -> Bool {
        for policy in policies {
            if !policy.isValid(for: input) {
                return false
            }
        }
        return true
    }
}

// Example Usage
let allowedChars = CharacterSet.alphanumerics
let lengthPolicy = LengthPolicy(minLength: 8, maxLength: 20)
let charPolicy = CharacterPolicy(allowedCharacters: allowedChars)

let validator = Validator(policies: [lengthPolicy, charPolicy])

let validString = "SwiftPolicy123"
let invalidStringLength = "Short"
let invalidStringChars = "SwiftPolicy!@#"

print("Valid string: \(validator.validate(input: validString))") // true
print("Invalid string (length): \(validator.validate(input: invalidStringLength))") // false
print("Invalid string (characters): \(validator.validate(input: invalidStringChars))") // false