CODESAMPLE

Pipes and Filters - Swift

Share on:

The Pipes and Filters pattern breaks down a complex task into a series of independent, self-contained processing steps (filters) connected by channels (pipes) through which data flows. Each filter performs a specific transformation on the input data and passes the result to the next filter. This promotes modularity, reusability, and simplifies testing.

This Swift implementation uses a protocol Filter to define the interface for each filter, requiring an execute method. A simple FilterChain manages the sequence of filters. Data is passed as strings to illustrate the flow, but could be any type. The code uses Swift’s protocol-oriented programming approach and functional style where appropriate (transformation within filters). This avoids excessive subclassing and keeps the filters lightweight and focused.

protocol Filter {
    func execute(input: String) -> String
}

struct StringToUppercaseFilter: Filter {
    func execute(input: String) -> String {
        input.uppercased()
    }
}

struct RemoveWhitespaceFilter: Filter {
    func execute(input: String) -> String {
        input.trimmingCharacters(in: .whitespacesAndNewlines)
    }
}

struct ExclaimifyFilter: Filter {
    func execute(input: String) -> String {
        input + "!"
    }
}

class FilterChain {
    private let filters: [Filter]

    init(filters: [Filter]) {
        self.filters = filters
    }

    func execute(input: String) -> String {
        var result = input
        for filter in filters {
            result = filter.execute(input: result)
        }
        return result
    }
}

// Example Usage:
let filters = [
    StringToUppercaseFilter(),
    RemoveWhitespaceFilter(),
    ExclaimifyFilter()
]

let chain = FilterChain(filters: filters)
let finalResult = chain.execute(input: "  hello world ")

print(finalResult) // Output: HELLO WORLD!