diff --git a/.gitignore b/.gitignore index 4896202..4e3bd38 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,7 @@ DerivedData .idea/ *.xcodeproj/xcuserdata +.swiftpm/xcode/xcuserdata/ +xcuserdata/ +*.log +test_output*.txt diff --git a/.swiftpm/xcode/xcuserdata/rickhohler.xcuserdatad/xcschemes/xcschememanagement.plist b/.swiftpm/xcode/xcuserdata/rickhohler.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 0f2a667..0000000 --- a/.swiftpm/xcode/xcuserdata/rickhohler.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,14 +0,0 @@ - - - - - SchemeUserState - - DesignAlgorithmsKit.xcscheme_^#shared#^_ - - orderHint - 10 - - - - diff --git a/CHANGELOG.md b/CHANGELOG.md index 840b9c1..80b086b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,23 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -### Added -- N/A - ### Changed -- N/A - -### Deprecated -- N/A +- README rewritten to match the code: purpose, products, platforms, dependencies, build/test, known issues ### Removed -- N/A +- `docs/DESIGN_PATTERNS.md` and `docs/EXAMPLES.md` (examples used APIs that do not exist; superseded by the README) +- Committed `.swiftpm/xcode/xcuserdata` (now git-ignored) -### Fixed -- N/A - -### Security -- N/A +### Notes +- Releases v1.8.0 (FilenameTokenizer, UUIDv5Generator), v1.9.0 (Visitor, Graph, Gzip) and v1.10.0 were tagged without CHANGELOG entries; backfill is tracked in `platform-and-test-hygiene` ## [1.7.0] - 2025-12-21 @@ -43,7 +35,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Boosted unit test coverage across multiple patterns (Builder, Factory, Adapter, Facade, Observer, Strategy) -- Added `AGENTS.md` release/tagging guideline documentation ## [v1.4.0] - 2025-12-12 diff --git a/Documentation.docc/DesignAlgorithmsKit.md b/Documentation.docc/DesignAlgorithmsKit.md index e0bef10..b1421ee 100644 --- a/Documentation.docc/DesignAlgorithmsKit.md +++ b/Documentation.docc/DesignAlgorithmsKit.md @@ -15,20 +15,20 @@ All patterns and algorithms follow consistent implementation guidelines for main ### Design Patterns #### Creational Patterns -- ``Singleton`` - Thread-safe singleton implementations -- ``Factory`` - Object creation without specifying concrete classes -- ``Builder`` - Step-by-step object construction with fluent API +- ``ThreadSafeSingleton`` - Thread-safe singleton base class +- ``ObjectFactory`` - Object creation without specifying concrete classes +- ``BaseBuilder`` - Step-by-step object construction #### Structural Patterns -- ``Facade`` - Simplified interface to complex subsystems -- ``Adapter`` - Adapting interfaces to client expectations +- ``BaseFacade`` - Simplified interface to complex subsystems +- ``BaseAdapter`` - Adapting interfaces to client expectations #### Behavioral Patterns -- ``Strategy`` - Interchangeable algorithms -- ``Observer`` - Event notification and subscription +- ``StrategyContext`` - Interchangeable algorithms +- ``BaseObservable`` - Event notification and subscription #### Modern Patterns -- ``Registry`` - Centralized type registration and discovery +- ``TypeRegistry`` / ``Registry`` - Centralized type and value registration ### Algorithms & Data Structures @@ -38,7 +38,8 @@ All patterns and algorithms follow consistent implementation guidelines for main - ``CountingBloomFilter`` - Bloom Filter variant that supports element removal #### Hashing -- ``HashAlgorithm`` - Protocol for hash algorithms +- ``HashAlgorithm`` - Supported hash algorithms (SHA-256, SHA-1, MD5, CRC-32) +- ``HashComputation`` - Hash computation helpers - ``SHA256`` - SHA-256 hash algorithm implementation ## Getting Started @@ -47,13 +48,13 @@ Add DesignAlgorithmsKit to your `Package.swift`: ```swift dependencies: [ - .package(url: "https://github.com/rickhohler/DesignAlgorithmsKit.git", from: "1.0.0") + .package(url: "https://github.com/nibbleware/DesignAlgorithmsKit.git", from: "1.0.0") ] ``` ## See Also -- [GitHub Repository](https://github.com/rickhohler/DesignAlgorithmsKit) +- [GitHub Repository](https://github.com/nibbleware/DesignAlgorithmsKit) - [Design Patterns Guide](https://en.wikipedia.org/wiki/Design_Patterns) - [Merkle Tree](https://en.wikipedia.org/wiki/Merkle_tree) - [Bloom Filter](https://en.wikipedia.org/wiki/Bloom_filter) diff --git a/README.md b/README.md index 7c15870..275007d 100644 --- a/README.md +++ b/README.md @@ -1,410 +1,101 @@ # DesignAlgorithmsKit -[![Tests](https://github.com/rickhohler/DesignAlgorithmsKit/workflows/Tests/badge.svg)](https://github.com/rickhohler/DesignAlgorithmsKit/actions) -[![codecov](https://codecov.io/gh/rickhohler/DesignAlgorithmsKit/branch/main/graph/badge.svg)](https://codecov.io/gh/rickhohler/DesignAlgorithmsKit) -[![Documentation](https://img.shields.io/badge/docs-DocC-blue)](https://rickhohler.github.io/DesignAlgorithmsKit/documentation/designalgorithmskit/) - -A Swift package providing common design patterns and algorithms with protocols and base types for extensibility. - -## Overview - -DesignAlgorithmsKit provides implementations of: -- **Design Patterns**: Classic patterns (Gang of Four) and modern patterns commonly used in Swift development -- **Algorithms**: Common algorithms and data structures (Merkle Tree, hashing, etc.) - -All patterns and algorithms follow consistent implementation guidelines for maintainability, testability, and extensibility. - -## Features - -### Creational Patterns -- **Singleton Pattern** - Thread-safe singleton implementations -- **Factory Pattern** - Object creation without specifying concrete classes -- **Builder Pattern** - Step-by-step object construction with fluent API -- **Prototype Pattern** - Object cloning and copying -- **Dependency Injection** - Protocol-based dependency injection - -### Structural Patterns -- **Adapter Pattern** - Adapting interfaces to client expectations -- **Facade Pattern** - Simplified interface to complex subsystems -- **Decorator Pattern** - Adding behavior to objects dynamically -- **Composite Pattern** - Composing objects into tree structures -- **Proxy Pattern** - Controlling access to objects - -### Behavioral Patterns -- **Strategy Pattern** - Interchangeable algorithms -- **Observer Pattern** - Event notification and subscription -- **Queue Processing Pattern** - Concurrent queue management with status tracking, progress monitoring, and retry support -- **Merging/Upsert Pattern** - Configurable merge strategies for conflict resolution -- **Command Pattern** - Encapsulating requests as objects -- **State Pattern** - Object behavior based on state -- **Template Method Pattern** - Defining algorithm skeleton -- **Chain of Responsibility** - Passing requests along a chain -- **Job Manager Pattern** - Orchestration of asynchronous tasks with status tracking -- **Pipeline Pattern** - Type-erased async processing pipeline -- **Iterator Pattern** - Traversing collections - -### Modern Patterns -- **Registry Pattern** - Centralized type registration and discovery -- **Provider Pattern** - Chain of responsibility for extensible behavior -- **Repository Pattern** - Data access abstraction - -### Algorithms & Data Structures -- **Merkle Tree** - Hash tree for efficient data verification -- **Bloom Filter** - Probabilistic data structure for membership testing -- **Counting Bloom Filter** - Bloom Filter variant that supports element removal -- **Hash Computation** - Unified cryptographic hash functions (SHA-256, SHA-1, MD5, CRC32) - -## Requirements - -- Swift 6.2+ -- macOS 10.15+ / iOS 13.0+ / tvOS 13.0+ / watchOS 6.0+ - -## Installation - -### Swift Package Manager - -Add DesignAlgorithmsKit to your `Package.swift`: - -```swift -dependencies: [ - .package(url: "https://github.com/rickhohler/DesignAlgorithmsKit.git", from: "1.0.0") -] -``` - -Or add it via Xcode: -1. File → Add Packages... -2. Enter the repository URL -3. Select version requirements +[![Tests](https://github.com/nibbleware/DesignAlgorithmsKit/workflows/Tests/badge.svg)](https://github.com/nibbleware/DesignAlgorithmsKit/actions) + +DesignAlgorithmsKit (DAK) is a general-purpose, domain-agnostic Swift library of reusable design patterns, concurrency helpers and algorithms. It has no dependencies of its own and must not contain file-system, platform, inventory or app concepts; generic code found in packages built on it belongs here. + +## Products + +One library product and target: **`DesignAlgorithmsKit`** (`Sources/DesignAlgorithmsKit`). + +| Area | Types | +| --- | --- | +| Registries | `TypeRegistry`, `Registrable`, `Registry` | +| Singletons | `ThreadSafeSingleton`, `Singleton`, `ActorSingleton`, `SingletonError` | +| Factory / builder | `ObjectFactory`, `FactoryProduct`, `FactoryError`, `BaseBuilder`, `BuilderError`, `ValidatingBuilderProtocol` | +| Thread-safe containers | `ThreadSafe`, `ThreadSafeArray`, `ThreadSafeDictionary` | +| Structural patterns | `BaseAdapter`, `BaseFacade`, `BaseDecorator`, `Composite`/`Leaf`/`BaseComponent` | +| Behavioral patterns | `StrategyContext`, `BaseStrategy`, `BaseObservable`/`Observer`, `CommandInvoker`/`ClosureCommand`, `BaseHandler`/`BaseTypedHandler`, `ArrayIterator`/`TreeIterator`, `Visitor`/`Visitable`, `Mergeable`/`MergeStrategy`/`DefaultMerger` | +| Pipelines | `DataPipeline`, `AsyncDataPipeline`, `AnyAsyncPipelineStage`, `DynamicAsyncPipeline`, `PipelineError` | +| Async work | `ProcessingQueue`/`QueueItem`/`QueueProcessor`, `JobManager`, `TaskOrchestrator`/`DAGTask`, `ResourceCoordinator` | +| Hashing | `HashAlgorithm` (SHA-256, SHA-1, MD5, CRC-32), `HashComputation`, `HashStrategy`/`HashStrategyRegistry`, `SHA256`, `Data.sha256`/`sha256Hex` | +| Identifiers | `ULID`, `UUIDv5Generator` | +| Probabilistic filters | `BloomFilter`, `CountingBloomFilter`, `BloomFilterHashable` | +| Merkle tree | `MerkleTree`, `MerkleProof`, `MerkleHashable` | +| Graphs | `Graph` (directed, BFS reachability, unreachable-node detection) | +| Compression | `Gzip` (in-memory GZIP via system zlib) | +| Encryption | `HybridEncryption` (Curve25519 + HKDF-SHA256 + ChaCha20-Poly1305) | +| Text / paths | `FilenameTokenizer`, `GitObjectLayout` | + +## Platforms + +`Package.swift` declares macOS 12 and iOS 15, with swift-tools-version 5.10. The library imports CryptoKit and links the system zlib, so in practice it builds only for Apple platforms. The older WASM, tvOS and watchOS claims are not backed by the build. + +## Dependencies + +- **Direct package dependencies:** none. The package links the system library `z` and uses Foundation and CryptoKit. +- **Tree** (`swift package show-dependencies`): + ``` + DesignAlgorithmsKit + └── (no external dependencies) + ``` +- **How consumers reference DAK.** The canonical remote is `https://github.com/nibbleware/DesignAlgorithmsKit.git`, and `rickhohler/DesignAlgorithmsKit` redirects to it. Use a semver range: + ```swift + .package(url: "https://github.com/nibbleware/DesignAlgorithmsKit.git", from: "1.10.0") + ``` + The latest tag is `v1.10.0` (the current `main`). ## Usage -### Registry Pattern - ```swift import DesignAlgorithmsKit -// Register a type -TypeRegistry.shared.register(MyType.self) +// Keyed registry (thread-safe) +final class CodecRegistry: Registry {} +let codecs = CodecRegistry() +codecs.register(MyCodec(), for: "my") -// Find registered type -if let type = TypeRegistry.shared.find(for: "myKey") { - // Use type +// Lazily created, per-type singleton +final class Settings: ThreadSafeSingleton { + override class func createShared() throws -> Settings { Settings() } } -``` +let settings = Settings.shared -### Factory Pattern +// Hashing +let hex = try HashComputation.computeHashHex(data: data, algorithm: .sha256) +let crc = HashComputation.computeCRC32(data: data) // 4 bytes, big-endian -```swift -import DesignAlgorithmsKit +// Identifiers +let id = UUIDv5Generator.generate(namespace: ns, name: "python.org") -// Create object via factory -let object = try ObjectFactory.shared.create(type: "myType", configuration: [:]) +// GZIP +let gz = try Gzip.compress(data: data) +let raw = try Gzip.decompress(data: gz) ``` -### Builder Pattern - -```swift -import DesignAlgorithmsKit +## Build & test -// Build complex object -let object = try MyObjectBuilder() - .setProperty1("value1") - .setProperty2(42) - .build() +```sh +swift build +swift test ``` -### Strategy Pattern - -```swift -import DesignAlgorithmsKit - -// Use strategy -let strategy: AlgorithmStrategy = ConcreteStrategy() -let result = strategy.execute(input) -``` +- No other packages are needed to build DAK. +- Current baseline: `swift build` succeeds with two warnings, and `swift test` runs 313 XCTest tests and 1 swift-testing placeholder with 0 failures. +- `IntegrationCompressionTests` runs `/usr/bin/gzip` and `/usr/bin/gunzip`, so it needs macOS. -### Observer Pattern +## Known issues -```swift -import DesignAlgorithmsKit - -// Subscribe to events -let observer = MyObserver() -subject.addObserver(observer) - -// Notify observers -subject.notifyObservers(event: .somethingHappened) -``` - -### Queue Processing Pattern - -```swift -import DesignAlgorithmsKit - -// Define your item type -struct MyItem: QueueItem { - let id: UUID - var status: QueueItemStatus = .pending - var progress: Double = 0.0 - let data: Data -} - -// Define your processor -struct MyProcessor: QueueProcessor { - typealias Item = MyItem - - func process(_ item: MyItem) async throws { - // Process the item - // Update progress if needed - } -} - -// Create and use the queue -let queue = ProcessingQueue( - processor: MyProcessor(), - maxConcurrent: 3 -) - -// Add items -let items = [MyItem(id: UUID(), data: data1), MyItem(id: UUID(), data: data2)] -await queue.add(items) - -// Monitor progress -let pending = await queue.pendingItems -let processing = await queue.processingItems -let completed = await queue.completedItems -let failed = await queue.failedItems - -// Retry failed items -if let failedItem = await queue.failedItems.first { - await queue.retry(id: failedItem.id) -} - -// Pause/resume -await queue.pause() -await queue.resume() -``` - -### Merging/Upsert Pattern - -```swift -import DesignAlgorithmsKit - -// Define your item type -struct MyItem: Mergeable { - let id: UUID - var name: String - var metadata: [String: String] -} - -// Create a merger -class MyMerger: DefaultMerger { - var storage: [UUID: MyItem] = [:] - - override func findExisting(by id: UUID) async -> MyItem? { - return storage[id] - } - - override func upsert(_ item: MyItem, strategy: MergeStrategy) async throws -> MyItem { - if let existing = await findExisting(by: item.id) { - let merged = merge(existing: existing, with: item, strategy: strategy) - storage[item.id] = merged - return merged - } else { - storage[item.id] = item - return item - } - } -} - -// Use the merger -let merger = MyMerger() - -// Upsert with prefer existing strategy -let item1 = MyItem(id: UUID(), name: "Item", metadata: ["key": "value"]) -let upserted1 = try await merger.upsert(item1, strategy: .preferExisting) - -// Upsert with prefer new strategy -let item2 = MyItem(id: item1.id, name: "Updated", metadata: ["key": "new"]) -let upserted2 = try await merger.upsert(item2, strategy: .preferNew) - -// Upsert with custom merge strategy -let customStrategy: MergeStrategy = .custom { existing, new in - let existingItem = existing as! MyItem - let newItem = new as! MyItem - var mergedMetadata = existingItem.metadata - mergedMetadata.merge(newItem.metadata) { _, new in new } - return MyItem( - id: existingItem.id, - name: newItem.name, - metadata: mergedMetadata - ) -} -let upserted3 = try await merger.upsert(item2, strategy: customStrategy) -``` - - -### Job Manager Pattern - -```swift -import DesignAlgorithmsKit - -// Initialize JobManager -let jobManager = JobManager(maxConcurrentJobs: 4) - -// Submit a job -let jobID = jobManager.submit(description: "Heavy Processing") { - // Perform async work - try await Task.sleep(nanoseconds: 1 * 1_000_000_000) - return "Success" -} - -// Check status (snapshot) -if let snapshot = await jobManager.getJob(id: jobID) { - print("Status: \(snapshot.status)") -} -``` - -### Pipeline Pattern (Dynamic Async) - -```swift -import DesignAlgorithmsKit - -// Create a dynamic pipeline -let pipeline = DynamicAsyncPipeline() - -// Add generic stages -pipeline.append(AnyAsyncPipelineStage(process: { input in - guard let text = input as? String else { throw PipelineError.invalidInputType(expected: "String", actual: "Unknown") } - return text.uppercased() -})) - -// Execute -let result = try await pipeline.execute(input: "hello world") -// Result: "HELLO WORLD" -``` - -### Merkle Tree - -```swift -import DesignAlgorithmsKit - -// Build Merkle tree from data -let data = ["block1", "block2", "block3", "block4"].map { $0.data(using: .utf8)! } -let tree = MerkleTree.build(from: data) - -// Get root hash -let rootHash = tree.rootHash - -// Generate proof for a specific leaf -if let proof = tree.generateProof(for: data[0]) { - // Verify proof - let isValid = MerkleTree.verify(proof: proof, rootHash: rootHash) -} -``` - -### Bloom Filter - -```swift -import DesignAlgorithmsKit - -// Create Bloom Filter with expected capacity and false positive rate -let filter = BloomFilter(capacity: 1000, falsePositiveRate: 0.01) - -// Add elements -filter.insert("element1") -filter.insert("element2") -filter.insert("element3") - -// Check membership -if filter.contains("element1") { - // Element might be in set (could be false positive) -} - -if !filter.contains("element4") { - // Element is definitely NOT in set -} - -// Use Counting Bloom Filter for removable elements -let countingFilter = CountingBloomFilter(capacity: 1000, falsePositiveRate: 0.01) -countingFilter.insert("item1") -countingFilter.remove("item1") -``` - -### Hash Computation - -```swift -import DesignAlgorithmsKit - -// Compute SHA256 hash -let data = "Hello, World!".data(using: .utf8)! -let hash = try HashComputation.computeHash(data: data, algorithm: .sha256) - -// Get hash as hex string -let hexHash = try HashComputation.computeHashHex(data: data, algorithm: .sha256) -// Result: "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f" - -// Use string algorithm names -let sha1Hash = try HashComputation.computeHashHex(data: data, algorithm: "sha1") - -// Convenience Data extensions -let quickHash = data.sha256Hex - -// Supported algorithms: SHA-256, SHA-1, MD5, CRC32 -let md5 = try HashComputation.computeHashHex(data: data, algorithm: .md5) -let crc = HashComputation.computeCRC32(data: data) -``` - -## Architecture - -DesignAlgorithmsKit is organized into modules: - -- **Core** - Base protocols and types -- **Creational** - Creational design patterns -- **Structural** - Structural design patterns -- **Behavioral** - Behavioral design patterns -- **Algorithms** - Algorithms and data structures - - **DataStructures** - Merkle Tree and other data structures - - **Cryptography** - Hash computation (SHA-256, SHA-1, MD5, CRC32) -- **Modern** - Modern patterns and extensions - -## Thread Safety - -All patterns are designed with thread safety in mind: -- **NSLock** - For traditional concurrency -- **Actor** - For Swift concurrency (Swift 5.5+) -- **Sendable** - Marked where appropriate +- `JobManager.cancel` does not stop a pending job; `TaskOrchestrator` never throws `taskFailure`; `ProcessingQueue` has a scheduling race; `ResourceCoordinator` releases locks late. +- Merkle proofs fail for unpaired leaves; Bloom filters trap on capacity 0, rate 0 or a negative `Int`; `Gzip.decompress` ignores the CRC and ISIZE trailer. +- `ULID` text is not compatible with the ULID specification. +- Platform claims are broader than tested, the `version` constant is stale (`1.3.0`), `WASMGuard.swift` is dead code, CRC/SHA code is duplicated, and the DocC catalog is not attached to the target. ## Documentation -- **[Full API Documentation (DocC)](https://rickhohler.github.io/DesignAlgorithmsKit/documentation/designalgorithmskit/)** - Complete API reference with interactive documentation -- [Design Patterns Guide](docs/DESIGN_PATTERNS.md) -- [Usage Examples](docs/EXAMPLES.md) - -You can also generate documentation locally: - -```bash -swift package generate-documentation --target DesignAlgorithmsKit -``` +- `Documentation.docc/`: DocC articles. They are not yet attached to the target. +- [CHANGELOG.md](CHANGELOG.md), [CONTRIBUTING.md](CONTRIBUTING.md), [SECURITY.md](SECURITY.md), [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). ## License -MIT License - see LICENSE file for details - -## Contributing - -> **Note**: This project is currently internal-only. External contributions are not accepted at this time. - -For internal contributors, please read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. - -Before contributing, please review: -- [Code of Conduct](CODE_OF_CONDUCT.md) -- [Security Policy](SECURITY.md) -- [Contributing Guidelines](CONTRIBUTING.md) - -## References - -- [Design Patterns: Elements of Reusable Object-Oriented Software (Gang of Four)](https://en.wikipedia.org/wiki/Design_Patterns) -- [Swift Design Patterns](https://softwarepatternslexicon.com/swift/introduction-to-design-patterns-in-swift/) -- [Apple Swift API Design Guidelines](https://www.swift.org/documentation/api-design-guidelines/) -- [Merkle Tree (Wikipedia)](https://en.wikipedia.org/wiki/Merkle_tree) +MIT. See [LICENSE](LICENSE). diff --git a/docs/DESIGN_PATTERNS.md b/docs/DESIGN_PATTERNS.md deleted file mode 100644 index 123af05..0000000 --- a/docs/DESIGN_PATTERNS.md +++ /dev/null @@ -1,355 +0,0 @@ -# Design Patterns Guide - -This guide provides an overview of the design patterns implemented in DesignAlgorithmsKit, their use cases, and examples. - -## Creational Patterns - -### Singleton Pattern - -Ensures a class has only one instance and provides global access to it. - -**Implementation**: `ThreadSafeSingleton`, `ActorSingleton` - -**Use Cases**: -- Configuration managers -- Logging systems -- Database connections -- Cache managers - -**Example**: -```swift -class AppConfig: ThreadSafeSingleton { - private override init() { - super.init() - // Initialize configuration - } - - override class func createShared() -> Self { - return Self() - } - - var apiKey: String = "" -} - -// Usage -AppConfig.shared.apiKey = "your-api-key" -``` - -### Factory Pattern - -Creates objects without specifying the exact class of object that will be created. - -**Implementation**: `ObjectFactory` - -**Use Cases**: -- Creating objects based on configuration -- Dependency injection -- Plugin systems - -**Example**: -```swift -class UserFactory: ObjectFactory { - static func create(type: String, configuration: [String: Any]) throws -> Any { - switch type { - case "admin": - return AdminUser(configuration: configuration) - case "regular": - return RegularUser(configuration: configuration) - default: - throw FactoryError.unknownType(type) - } - } -} -``` - -### Builder Pattern - -Constructs complex objects step by step with a fluent API. - -**Implementation**: `BaseBuilder` - -**Use Cases**: -- Creating complex objects with many optional parameters -- Immutable object construction -- Configuration objects - -**Example**: -```swift -class HTTPRequestBuilder: BaseBuilder { - private var url: URL? - private var method: String = "GET" - private var headers: [String: String] = [:] - - func setURL(_ url: URL) -> Self { - self.url = url - return self - } - - func setMethod(_ method: String) -> Self { - self.method = method - return self - } - - func addHeader(_ key: String, value: String) -> Self { - self.headers[key] = value - return self - } - - override func build() throws -> HTTPRequest { - guard let url = url else { - throw BuilderError.missingRequiredProperty("url") - } - return HTTPRequest(url: url, method: method, headers: headers) - } -} - -// Usage -let request = try HTTPRequestBuilder() - .setURL(URL(string: "https://api.example.com")!) - .setMethod("POST") - .addHeader("Content-Type", value: "application/json") - .build() -``` - -## Structural Patterns - -### Adapter Pattern - -Allows objects with incompatible interfaces to work together. - -**Implementation**: `Adapter` protocol - -**Use Cases**: -- Integrating third-party libraries -- Legacy code integration -- Interface compatibility - -**Example**: -```swift -protocol PaymentProcessor { - func processPayment(amount: Double) -> Bool -} - -class LegacyPaymentSystem { - func pay(amount: Double) -> Bool { - // Legacy implementation - return true - } -} - -class LegacyPaymentAdapter: Adapter { - typealias Adaptee = LegacyPaymentSystem - typealias Target = PaymentProcessor - - private let adaptee: Adaptee - - init(adaptee: Adaptee) { - self.adaptee = adaptee - } - - func adapt() -> Target { - return AdaptedPaymentProcessor(adaptee: adaptee) - } -} - -class AdaptedPaymentProcessor: PaymentProcessor { - private let adaptee: LegacyPaymentSystem - - init(adaptee: LegacyPaymentSystem) { - self.adaptee = adaptee - } - - func processPayment(amount: Double) -> Bool { - return adaptee.pay(amount: amount) - } -} -``` - -### Facade Pattern - -Provides a simplified interface to a complex subsystem. - -**Implementation**: `Facade` protocol - -**Use Cases**: -- Simplifying complex APIs -- Hiding implementation details -- Providing a unified interface - -**Example**: -```swift -class MediaPlayerFacade: Facade { - private let audioPlayer = AudioPlayer() - private let videoPlayer = VideoPlayer() - private let subtitleManager = SubtitleManager() - - func play(media: Media) { - switch media.type { - case .audio: - audioPlayer.play(media.url) - case .video: - videoPlayer.play(media.url) - subtitleManager.load(media.subtitleURL) - } - } - - func stop() { - audioPlayer.stop() - videoPlayer.stop() - subtitleManager.hide() - } -} -``` - -## Behavioral Patterns - -### Strategy Pattern - -Defines a family of algorithms, encapsulates each one, and makes them interchangeable. - -**Implementation**: `Strategy` protocol, `StrategyContext` - -**Use Cases**: -- Algorithm selection at runtime -- Different sorting strategies -- Payment processing methods - -**Example**: -```swift -struct QuickSortStrategy: Strategy { - func execute(_ input: [T]) -> [T] { - // Quick sort implementation - return input.sorted() - } -} - -struct MergeSortStrategy: Strategy { - func execute(_ input: [T]) -> [T] { - // Merge sort implementation - return input.sorted() - } -} - -// Usage -let context = StrategyContext(strategy: QuickSortStrategy()) -let sorted = context.execute([3, 1, 4, 1, 5, 9, 2, 6]) -``` - -### Observer Pattern - -Defines a one-to-many dependency between objects so that when one object changes state, all dependents are notified. - -**Implementation**: `Observer` protocol, `Observable` protocol, `BaseObservable` - -**Use Cases**: -- Event handling systems -- Model-View architectures -- Notification systems - -**Example**: -```swift -class DataModel: BaseObservable { - private var value: String = "" { - didSet { - notifyObservers(event: value) - } - } - - func updateValue(_ newValue: String) { - value = newValue - } -} - -class ViewController: Observer { - func didReceiveNotification(from observable: any Observable, event: Any) { - if let value = event as? String { - print("Value updated to: \(value)") - } - } -} - -// Usage -let model = DataModel() -let viewController = ViewController() -model.addObserver(viewController) -model.updateValue("Hello, World!") -``` - -## Modern Patterns - -### Registry Pattern - -Provides centralized type registration and discovery. - -**Implementation**: `TypeRegistry` - -**Use Cases**: -- Plugin systems -- Dependency injection containers -- Type factories - -**Example**: -```swift -// Register types -TypeRegistry.shared.register(UserService.self, forKey: "userService") -TypeRegistry.shared.register(ProductService.self, forKey: "productService") - -// Retrieve types -if let userServiceType = TypeRegistry.shared.find(for: "userService") { - let service = userServiceType.init() - // Use service -} -``` - -## Choosing the Right Pattern - -### When to Use Singleton -- You need exactly one instance of a class -- Global access is required -- Resource management (database connections, caches) - -### When to Use Factory -- Object creation logic is complex -- You want to decouple object creation from usage -- You need to create objects based on runtime conditions - -### When to Use Builder -- Object has many optional parameters -- You want immutable objects -- Step-by-step construction is clearer than a large initializer - -### When to Use Adapter -- You need to integrate incompatible interfaces -- Working with legacy code -- Third-party library integration - -### When to Use Facade -- You want to simplify a complex subsystem -- Hide implementation details -- Provide a unified interface - -### When to Use Strategy -- You have multiple ways to accomplish a task -- Algorithm selection at runtime -- You want to avoid conditional statements for algorithm selection - -### When to Use Observer -- You need to notify multiple objects of state changes -- Decoupling senders and receivers -- Event-driven architectures - -## Best Practices - -1. **Prefer Protocols**: Use protocols to define interfaces, making patterns more flexible and testable -2. **Thread Safety**: Consider thread safety for singletons and shared state -3. **Swift Concurrency**: Use actors for thread-safe singletons in async/await contexts -4. **Immutability**: Prefer immutable objects where possible -5. **Testability**: Design patterns should make code more testable, not less -6. **Documentation**: Document when and why to use each pattern - -## References - -- [Design Patterns: Elements of Reusable Object-Oriented Software](https://en.wikipedia.org/wiki/Design_Patterns) -- [Swift Design Patterns](https://softwarepatternslexicon.com/swift/introduction-to-design-patterns-in-swift/) -- [Apple Swift API Design Guidelines](https://www.swift.org/documentation/api-design-guidelines/) - diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md deleted file mode 100644 index 1cea42f..0000000 --- a/docs/EXAMPLES.md +++ /dev/null @@ -1,555 +0,0 @@ -# Usage Examples - -This document provides practical examples of using DesignAlgorithmsKit in real-world scenarios. - -## Table of Contents - -- [Creational Patterns](#creational-patterns) -- [Structural Patterns](#structural-patterns) -- [Behavioral Patterns](#behavioral-patterns) -- [Algorithms & Data Structures](#algorithms--data-structures) - -## Creational Patterns - -### Singleton: Application Configuration - -```swift -import DesignAlgorithmsKit - -class AppConfiguration: ThreadSafeSingleton { - private var settings: [String: Any] = [:] - - private override init() { - super.init() - loadConfiguration() - } - - override class func createShared() -> Self { - return Self() - } - - func get(_ key: String, default: T) -> T { - return settings[key] as? T ?? `default` - } - - func set(_ key: String, value: T) { - settings[key] = value - } - - private func loadConfiguration() { - // Load from UserDefaults, file, etc. - settings["apiURL"] = "https://api.example.com" - settings["timeout"] = 30 - } -} - -// Usage -let config = AppConfiguration.shared -let apiURL: String = config.get("apiURL", default: "") -config.set("debugMode", value: true) -``` - -### Factory: Creating UI Components - -```swift -import DesignAlgorithmsKit - -protocol UIComponent { - func render() -} - -class Button: UIComponent { - let title: String - init(title: String) { self.title = title } - func render() { print("Button: \(title)") } -} - -class TextField: UIComponent { - let placeholder: String - init(placeholder: String) { self.placeholder = placeholder } - func render() { print("TextField: \(placeholder)") } -} - -class UIComponentFactory: ObjectFactory { - static func create(type: String, configuration: [String: Any]) throws -> Any { - switch type { - case "button": - guard let title = configuration["title"] as? String else { - throw FactoryError.invalidConfiguration("title required") - } - return Button(title: title) - case "textField": - guard let placeholder = configuration["placeholder"] as? String else { - throw FactoryError.invalidConfiguration("placeholder required") - } - return TextField(placeholder: placeholder) - default: - throw FactoryError.unknownType(type) - } - } -} - -// Usage -let button = try UIComponentFactory.create( - type: "button", - configuration: ["title": "Click Me"] -) as! Button -button.render() -``` - -### Builder: HTTP Request Construction - -```swift -import DesignAlgorithmsKit -import Foundation - -struct HTTPRequest { - let url: URL - let method: String - let headers: [String: String] - let body: Data? -} - -class HTTPRequestBuilder: BaseBuilder { - private var url: URL? - private var method: String = "GET" - private var headers: [String: String] = [:] - private var body: Data? - - func setURL(_ url: URL) -> Self { - self.url = url - return self - } - - func setMethod(_ method: String) -> Self { - self.method = method - return self - } - - func addHeader(_ key: String, value: String) -> Self { - self.headers[key] = value - return self - } - - func setBody(_ data: Data) -> Self { - self.body = data - return self - } - - override func build() throws -> HTTPRequest { - guard let url = url else { - throw BuilderError.missingRequiredProperty("url") - } - return HTTPRequest(url: url, method: method, headers: headers, body: body) - } -} - -// Usage -let request = try HTTPRequestBuilder() - .setURL(URL(string: "https://api.example.com/users")!) - .setMethod("POST") - .addHeader("Content-Type", value: "application/json") - .addHeader("Authorization", value: "Bearer token123") - .setBody("{\"name\":\"John\"}".data(using: .utf8)!) - .build() -``` - -## Structural Patterns - -### Adapter: Integrating Third-Party Services - -```swift -import DesignAlgorithmsKit - -// Your application's payment interface -protocol PaymentService { - func charge(amount: Double, currency: String) -> Bool -} - -// Third-party payment service (incompatible interface) -class StripePaymentService { - func processPayment(amountInCents: Int, currencyCode: String) -> Bool { - // Stripe-specific implementation - print("Processing \(amountInCents) cents in \(currencyCode)") - return true - } -} - -// Adapter to make Stripe compatible with your interface -class StripePaymentAdapter: Adapter { - typealias Adaptee = StripePaymentService - typealias Target = PaymentService - - private let adaptee: Adaptee - - init(adaptee: Adaptee) { - self.adaptee = adaptee - } - - func adapt() -> Target { - return AdaptedStripeService(adaptee: adaptee) - } -} - -class AdaptedStripeService: PaymentService { - private let adaptee: StripePaymentService - - init(adaptee: StripePaymentService) { - self.adaptee = adaptee - } - - func charge(amount: Double, currency: String) -> Bool { - let amountInCents = Int(amount * 100) - return adaptee.processPayment(amountInCents: amountInCents, currencyCode: currency) - } -} - -// Usage -let stripe = StripePaymentService() -let adapter = StripePaymentAdapter(adaptee: stripe) -let paymentService: PaymentService = adapter.adapt() -paymentService.charge(amount: 29.99, currency: "USD") -``` - -### Facade: Simplifying Complex Subsystem - -```swift -import DesignAlgorithmsKit - -// Complex subsystem components -class AuthenticationService { - func authenticate(username: String, password: String) -> Bool { - // Complex authentication logic - return username == "admin" && password == "password" - } -} - -class AuthorizationService { - func authorize(user: String, resource: String) -> Bool { - // Complex authorization logic - return true - } -} - -class AuditService { - func log(action: String, user: String) { - print("Audit: \(user) performed \(action)") - } -} - -// Facade to simplify access -class SecurityFacade: Facade { - private let auth = AuthenticationService() - private let authz = AuthorizationService() - private let audit = AuditService() - - func login(username: String, password: String) -> Bool { - let authenticated = auth.authenticate(username: username, password: password) - if authenticated { - audit.log(action: "login", user: username) - } - return authenticated - } - - func accessResource(user: String, resource: String) -> Bool { - let authorized = authz.authorize(user: user, resource: resource) - if authorized { - audit.log(action: "access", user: user) - } - return authorized - } -} - -// Usage -let security = SecurityFacade() -if security.login(username: "admin", password: "password") { - security.accessResource(user: "admin", resource: "sensitive-data") -} -``` - -## Behavioral Patterns - -### Strategy: Sorting Algorithms - -```swift -import DesignAlgorithmsKit - -struct BubbleSortStrategy: Strategy { - func execute(_ input: [T]) -> [T] { - var array = input - for i in 0.. array[j + 1] { - array.swapAt(j, j + 1) - } - } - } - return array - } -} - -struct QuickSortStrategy: Strategy { - func execute(_ input: [T]) -> [T] { - guard input.count > 1 else { return input } - let pivot = input[input.count / 2] - let less = input.filter { $0 < pivot } - let equal = input.filter { $0 == pivot } - let greater = input.filter { $0 > pivot } - return execute(less) + equal + execute(greater) - } -} - -// Usage -let numbers = [64, 34, 25, 12, 22, 11, 90] - -let bubbleContext = StrategyContext(strategy: BubbleSortStrategy()) -let bubbleSorted = bubbleContext.execute(numbers) -print("Bubble Sort: \(bubbleSorted)") - -let quickContext = StrategyContext(strategy: QuickSortStrategy()) -let quickSorted = quickContext.execute(numbers) -print("Quick Sort: \(quickSorted)") -``` - -### Observer: Event Notification System - -```swift -import DesignAlgorithmsKit - -class EventPublisher: BaseObservable { - func publishEvent(_ event: String) { - notifyObservers(event: event) - } -} - -class EmailNotifier: Observer { - func didReceiveNotification(from observable: any Observable, event: Any) { - if let event = event as? String { - print("Email: Event '\(event)' occurred") - } - } -} - -class SMSNotifier: Observer { - func didReceiveNotification(from observable: any Observable, event: Any) { - if let event = event as? String { - print("SMS: Event '\(event)' occurred") - } - } -} - -// Usage -let publisher = EventPublisher() -let emailNotifier = EmailNotifier() -let smsNotifier = SMSNotifier() - -publisher.addObserver(emailNotifier) -publisher.addObserver(smsNotifier) - -publisher.publishEvent("User registered") -publisher.publishEvent("Order placed") -``` - -## Algorithms & Data Structures - -### Merkle Tree: Data Verification - -```swift -import DesignAlgorithmsKit -import Foundation - -// Create data blocks -let block1 = "Transaction 1".data(using: .utf8)! -let block2 = "Transaction 2".data(using: .utf8)! -let block3 = "Transaction 3".data(using: .utf8)! -let block4 = "Transaction 4".data(using: .utf8)! - -let blocks = [block1, block2, block3, block4] - -// Build Merkle tree -let tree = MerkleTree.build(from: blocks) -let rootHash = tree.rootHash - -print("Root hash: \(rootHash.map { String(format: "%02x", $0) }.joined())") - -// Generate proof for a specific block -if let proof = tree.generateProof(for: block1) { - // Verify proof - let isValid = MerkleTree.verify(proof: proof, rootHash: rootHash) - print("Proof valid: \(isValid)") -} -``` - -### Bloom Filter: Membership Testing - -```swift -import DesignAlgorithmsKit - -// Create Bloom Filter with capacity 1000 and 1% false positive rate -let filter = BloomFilter(capacity: 1000, falsePositiveRate: 0.01) - -// Add items -filter.insert("apple") -filter.insert("banana") -filter.insert("cherry") - -// Test membership -print(filter.contains("apple")) // true -print(filter.contains("banana")) // true -print(filter.contains("grape")) // false (or possibly true due to false positive) -``` - -### Hash Algorithm: Data Hashing - -```swift -import DesignAlgorithmsKit -import Foundation - -// Hash data -let data = "Hello, World!".data(using: .utf8)! -let hash = SHA256.hash(data: data) -print("SHA-256 hash: \(hash.map { String(format: "%02x", $0) }.joined())") - -// Using Data extension (New in 1.1.1) -let hexHash = data.sha256Hex -print("SHA-256 hex: \(hexHash)") - -// Hash string directly -let stringHash = SHA256.hash(string: "Hello, World!") -print("String hash: \(stringHash.map { String(format: "%02x", $0) }.joined())") -``` - -### Counting Bloom Filter: With Removal Support - -```swift -import DesignAlgorithmsKit - -// Create Counting Bloom Filter -let countingFilter = CountingBloomFilter(capacity: 1000, falsePositiveRate: 0.01) - -// Add items -countingFilter.insert("item1") -countingFilter.insert("item2") -countingFilter.insert("item3") - -// Check membership -print(countingFilter.contains("item1")) // true - -// Remove item -countingFilter.remove("item1") -print(countingFilter.contains("item1")) // false -``` - -## Complete Example: E-Commerce System - -```swift -import DesignAlgorithmsKit -import Foundation - -// Configuration Singleton -class ECommerceConfig: ThreadSafeSingleton { - private override init() { - super.init() - } - - override class func createShared() -> Self { - return Self() - } - - var apiBaseURL = "https://api.ecommerce.com" - var maxRetries = 3 -} - -// Product Builder -struct Product { - let id: String - let name: String - let price: Double - let description: String? -} - -class ProductBuilder: BaseBuilder { - private var id: String? - private var name: String? - private var price: Double? - private var description: String? - - func setId(_ id: String) -> Self { - self.id = id - return self - } - - func setName(_ name: String) -> Self { - self.name = name - return self - } - - func setPrice(_ price: Double) -> Self { - self.price = price - return self - } - - func setDescription(_ description: String) -> Self { - self.description = description - return self - } - - override func build() throws -> Product { - guard let id = id, - let name = name, - let price = price else { - throw BuilderError.missingRequiredProperty("id, name, or price") - } - return Product(id: id, name: name, price: price, description: description) - } -} - -// Event Observer -class OrderObserver: Observer { - func didReceiveNotification(from observable: any Observable, event: Any) { - if let orderId = event as? String { - print("Order \(orderId) has been placed!") - } - } -} - -class OrderService: BaseObservable { - func placeOrder(product: Product) { - // Process order - print("Placing order for \(product.name)") - notifyObservers(event: UUID().uuidString) - } -} - -// Usage -let config = ECommerceConfig.shared -print("API URL: \(config.apiBaseURL)") - -let product = try ProductBuilder() - .setId("123") - .setName("iPhone 15") - .setPrice(999.99) - .setDescription("Latest iPhone model") - .build() - -let orderService = OrderService() -let observer = OrderObserver() -orderService.addObserver(observer) - -orderService.placeOrder(product: product) -``` - -## Best Practices - -1. **Use Singletons Sparingly**: Only when you truly need a single instance -2. **Prefer Protocols**: Use protocols for better testability and flexibility -3. **Immutable Builders**: Consider making builder products immutable -4. **Error Handling**: Always handle errors from builders and factories -5. **Thread Safety**: Be aware of thread safety when using shared state -6. **Documentation**: Document your pattern usage for future maintainers - -## See Also - -- [Design Patterns Guide](DESIGN_PATTERNS.md) -- [Full API Documentation](https://rickhohler.github.io/DesignAlgorithmsKit/documentation/designalgorithmskit/) -