Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions Sources/DesignAlgorithmsKit/Behavioral/ChainOfResponsibility.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//
// ChainOfResponsibility.swift
// DesignAlgorithmsKit
//
// Chain of Responsibility Pattern - Pass requests along a chain of handlers
//

import Foundation

/// Protocol for a handler in the chain
public protocol Handler: AnyObject {
/// The next handler in the chain
var nextHandler: Handler? { get set }

/// Handle a request
/// - Parameter request: The request to handle
/// - Returns: Result if handled, nil otherwise
func handle(_ request: Any) -> Any?
}

/// Base implementation of a handler
open class BaseHandler: Handler {
public var nextHandler: Handler?

public init(next: Handler? = nil) {
self.nextHandler = next
}

/// Set the next handler in the chain
/// - Parameter handler: The next handler
/// - Returns: The handler that was set (for chaining)
@discardableResult
public func setNext(_ handler: Handler) -> Handler {
self.nextHandler = handler
return handler
}

open func handle(_ request: Any) -> Any? {
if let next = nextHandler {
return next.handle(request)
}
return nil
}
}

/// A type-safe version of the Chain of Responsibility
public protocol TypedHandler: AnyObject {
associatedtype Request
associatedtype Response

var nextHandler: (any TypedHandler)? { get set }

func handle(_ request: Request) -> Response?
}

/// Base implementation for typed handlers
open class BaseTypedHandler<T, R>: TypedHandler {
public typealias Request = T
public typealias Response = R

// We use a type-erased wrapper or force cast internally because generic protocols as types are tricky
// For simplicity in this generic pattern library, we'll store specific typed handler
public var nextTypedHandler: BaseTypedHandler<T, R>?

// Conformance to protocol (computed property due to associatedtype limits)
public var nextHandler: (any TypedHandler)? {
get { return nextTypedHandler }
set { nextTypedHandler = newValue as? BaseTypedHandler<T, R> }
}

public init() {}

@discardableResult
public func setNext(_ handler: BaseTypedHandler<T, R>) -> BaseTypedHandler<T, R> {
self.nextTypedHandler = handler
return handler
}

open func handle(_ request: T) -> R? {
return nextTypedHandler?.handle(request)
}
}
78 changes: 78 additions & 0 deletions Sources/DesignAlgorithmsKit/Behavioral/Command.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//
// Command.swift
// DesignAlgorithmsKit
//
// Command Pattern - Encapsulate a request as an object
//

import Foundation

/// Protocol for commands
public protocol Command {
/// Execute the command
func execute()

/// Undo the command (optional)
func undo()
}

/// Base command implementation
open class BaseCommand: Command {
public init() {}

open func execute() {
// To be implemented by subclasses
}

open func undo() {
// To be implemented by subclasses
}
}

/// A command that wraps a simple closure
public class ClosureCommand: Command {
private let action: () -> Void
private let undoAction: (() -> Void)?

public init(action: @escaping () -> Void, undoAction: (() -> Void)? = nil) {
self.action = action
self.undoAction = undoAction
}

public func execute() {
action()
}

public func undo() {
undoAction?()
}
}

/// Invoker responsible for executing commands
open class CommandInvoker {
private var history: [Command] = []
private var undoStack: [Command] = []

public init() {}

/// Execute a command
public func execute(_ command: Command) {
command.execute()
history.append(command)
undoStack.removeAll() // Clear redo stack on new operation
}

/// Undo the last command
public func undo() {
guard let command = history.popLast() else { return }
command.undo()
undoStack.append(command)
}

/// Redo the last undone command
public func redo() {
guard let command = undoStack.popLast() else { return }
command.execute()
history.append(command)
}
}
74 changes: 74 additions & 0 deletions Sources/DesignAlgorithmsKit/Behavioral/Iterator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//
// Iterator.swift
// DesignAlgorithmsKit
//
// Iterator Pattern - Access elements of a collection consistently
//

import Foundation

/// Protocol for iterators
public protocol Iterator {
associatedtype Element

/// Check if there are more elements
func hasNext() -> Bool

/// Get the next element
func next() -> Element?
}

/// Protocol for iterable aggregates
public protocol Iterable {
associatedtype IteratorType: Iterator

/// Create an iterator
func makeIterator() -> IteratorType
}

/// A concrete iterator for array-based collections
public class ArrayIterator<T>: Iterator {
private let items: [T]
private var currentIndex = 0

public init(_ items: [T]) {
self.items = items
}

public func hasNext() -> Bool {
return currentIndex < items.count
}

public func next() -> T? {
guard hasNext() else { return nil }
let item = items[currentIndex]
currentIndex += 1
return item
}
}

/// A concrete iterator for tree structures (depth-first)
public class TreeIterator<T>: Iterator {
private var stack: [T] = []
private let getChildren: (T) -> [T]

public init(root: T, getChildren: @escaping (T) -> [T]) {
self.stack = [root]
self.getChildren = getChildren
}

public func hasNext() -> Bool {
return !stack.isEmpty
}

public func next() -> T? {
guard !stack.isEmpty else { return nil }
let current = stack.removeLast()
// Add children to stack in reverse order to process them in original order
let children = getChildren(current)
for child in children.reversed() {
stack.append(child)
}
return current
}
}
99 changes: 99 additions & 0 deletions Sources/DesignAlgorithmsKit/Behavioral/Pipeline.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//
// Pipeline.swift
// DesignAlgorithmsKit
//
// Pipeline Pattern - Process data through a sequence of stages
//

import Foundation

/// Protocol for a pipeline stage
public protocol DataPipelineStage {
/// The input type for this stage
associatedtype Input

/// The output type for this stage
associatedtype Output

/// Process the input and produce output
/// - Parameter input: Input data
/// - Returns: Processed output
/// - Throws: Error if processing fails
func process(_ input: Input) throws -> Output
}

/// Protocol for an asynchronous pipeline stage
public protocol AsyncDataPipelineStage {
/// The input type for this stage
associatedtype Input

/// The output type for this stage
associatedtype Output

/// Process the input asynchronously
/// - Parameter input: Input data
/// - Returns: Processed output
/// - Throws: Error if processing fails
func process(_ input: Input) async throws -> Output
}

/// A pipeline that executes stages sequentially
///
/// The pipeline pattern allows processing data through a sequence of stages,
/// where the output of one stage becomes the input of the next.
open class DataPipeline<Input, Output> {
private let operation: (Input) throws -> Output

/// Initialize with a processing function
public init(_ operation: @escaping (Input) throws -> Output) {
self.operation = operation
}

/// Execute the pipeline
public func execute(_ input: Input) throws -> Output {
return try operation(input)
}

/// Append a new stage to the pipeline
public func appending<S: DataPipelineStage>(_ stage: S) -> DataPipeline<Input, S.Output> where S.Input == Output {
return DataPipeline<Input, S.Output> { input in
let intermediate = try self.execute(input)
return try stage.process(intermediate)
}
}

/// Append a closure stage
public func appending<NewOutput>(_ closure: @escaping (Output) throws -> NewOutput) -> DataPipeline<Input, NewOutput> {
return DataPipeline<Input, NewOutput> { input in
let intermediate = try self.execute(input)
return try closure(intermediate)
}
}
}

/// An asynchronous pipeline
open class AsyncDataPipeline<Input, Output> {
private let operation: (Input) async throws -> Output

public init(_ operation: @escaping (Input) async throws -> Output) {
self.operation = operation
}

public func execute(_ input: Input) async throws -> Output {
return try await operation(input)
}

public func appending<S: AsyncDataPipelineStage>(_ stage: S) -> AsyncDataPipeline<Input, S.Output> where S.Input == Output {
return AsyncDataPipeline<Input, S.Output> { input in
let intermediate = try await self.execute(input)
return try await stage.process(intermediate)
}
}

public func appending<NewOutput>(_ closure: @escaping (Output) async throws -> NewOutput) -> AsyncDataPipeline<Input, NewOutput> {
return AsyncDataPipeline<Input, NewOutput> { input in
let intermediate = try await self.execute(input)
return try await closure(intermediate)
}
}
}
Loading