Section 7/81 menit
7. Real Use Cases
7. Real Use Cases
Use Case 1: Multi-Parameter Validator
swift
import Foundation
// Protocol untuk semua validatable types
protocol Validatable {
associatedtype Value
func validate(_ value: Value) -> ValidationResult
}
struct ValidationResult {
let isValid: Bool
let fieldName: String
let errorMessage: String?
static func success(_ field: String) -> ValidationResult {
ValidationResult(isValid: true, fieldName: field, errorMessage: nil)
}
static func failure(_ field: String, message: String) -> ValidationResult {
ValidationResult(isValid: false, fieldName: field, errorMessage: message)
}
}
struct StringValidator: Validatable {
let fieldName: String
let minLength: Int
let maxLength: Int
func validate(_ value: String) -> ValidationResult {
if value.count < minLength {
return .failure(fieldName, message: "Minimal \(minLength) karakter")
}
if value.count > maxLength {
return .failure(fieldName, message: "Maksimal \(maxLength) karakter")
}
return .success(fieldName)
}
}
struct RangeValidator<T: Comparable>: Validatable {
let fieldName: String
let range: ClosedRange<T>
func validate(_ value: T) -> ValidationResult {
range.contains(value)
? .success(fieldName)
: .failure(fieldName, message: "Harus di antara \(range.lowerBound) dan \(range.upperBound)")
}
}
// Form validation engine menggunakan pack
struct FormValidator {
// Validate banyak field sekaligus dengan tipe berbeda
static func validate<each V: Validatable>(
pairs: repeat (each V, (each V).Value)
) -> [ValidationResult] {
var results: [ValidationResult] = []
for (validator, value) in repeat each pairs {
results.append(validator.validate(value))
}
return results
}
static func allValid(_ results: [ValidationResult]) -> Bool {
results.allSatisfy { $0.isValid }
}
}
// Penggunaan:
struct RegistrationForm {
var username: String
var age: Int
var bio: String
}
func validateRegistrationForm(_ form: RegistrationForm) -> [ValidationResult] {
let usernameValidator = StringValidator(fieldName: "username", minLength: 3, maxLength: 30)
let ageValidator = RangeValidator(fieldName: "age", range: 13...120)
let bioValidator = StringValidator(fieldName: "bio", minLength: 0, maxLength: 500)
return FormValidator.validate(pairs:
(usernameValidator, form.username),
(ageValidator, form.age),
(bioValidator, form.bio)
)
}
let form = RegistrationForm(username: "ari", age: 28, bio: "iOS Developer")
let results = validateRegistrationForm(form)
let errors = results.filter { !$0.isValid }
print(errors.isEmpty ? "Form valid!" : "Errors: \(errors.map { $0.errorMessage ?? "" })")
Use Case 2: Type-Safe Observable Properties
swift
// Observer pattern untuk multiple property types
protocol PropertyObserver: AnyObject {
associatedtype Value
func valueChanged(to newValue: Value)
}
class PropertyStore {
// Notifikasi multiple observer dengan tipe berbeda sekaligus
func notifyObservers<each O: PropertyObserver>(
_ observers: repeat each O,
with values: repeat (each O).Value
) {
for (observer, value) in repeat each (observers, values) {
observer.valueChanged(to: value)
}
}
}
// Konkret observer types
class IntObserver: PropertyObserver {
var lastValue: Int?
func valueChanged(to newValue: Int) { lastValue = newValue }
}
class StringObserver: PropertyObserver {
var lastValue: String?
func valueChanged(to newValue: String) { lastValue = newValue }
}
class BoolObserver: PropertyObserver {
var lastValue: Bool?
func valueChanged(to newValue: Bool) { lastValue = newValue }
}
// Penggunaan
let store = PropertyStore()
let countObserver = IntObserver()
let nameObserver = StringObserver()
let activeObserver = BoolObserver()
store.notifyObservers(
countObserver, nameObserver, activeObserver,
with: 42, "Ari", true
)
print(countObserver.lastValue!) // 42
print(nameObserver.lastValue!) // "Ari"
print(activeObserver.lastValue!) // true
Use Case 3: Dependency Container
swift
// Type-safe dependency injection container
protocol Injectable {
init()
}
class DependencyContainer {
// Resolve multiple dependencies sekaligus, type-safe
func resolve<each D: Injectable>(_ types: repeat (each D).Type) -> (repeat each D) {
(repeat (each types).init())
}
// Make dan configure
func make<each D: Injectable & Configurable>(
_ types: repeat (each D).Type,
configurations: repeat Configuration<each D>
) -> (repeat each D) {
var instances = (repeat (each types).init())
for (instance, config) in repeat each (instances, configurations) {
// Ini tidak langsung bisa karena tuple mutation
// Tapi konsepnya benar
}
return instances
}
}
protocol Configurable {
mutating func configure(with config: [String: Any])
}
struct Configuration<T> {
let values: [String: Any]
}
// Services
struct UserService: Injectable {
init() { print("UserService initialized") }
}
struct AuthService: Injectable {
init() { print("AuthService initialized") }
}
struct AnalyticsService: Injectable {
init() { print("AnalyticsService initialized") }
}
// Penggunaan
let container = DependencyContainer()
let (userService, authService, analyticsService) = container.resolve(
UserService.self,
AuthService.self,
AnalyticsService.self
)
// Semua diinstansiasi, tipe-nya diketahui compiler
Use Case 4: Assertion Helper untuk Testing
swift
import Testing
// Type-safe assertion untuk banyak nilai sekaligus
func assertAll<each T: Equatable>(
_ label: String,
pairs: repeat (actual: each T, expected: each T),
sourceLocation: SourceLocation = #_sourceLocation
) {
var allPassed = true
var failureMessages: [String] = []
for (actual, expected) in repeat each pairs {
if actual != expected {
allPassed = false
failureMessages.append(" Expected \(expected), got \(actual)")
}
}
if !allPassed {
let message = "\(label) assertion(s) failed:\n" + failureMessages.joined(separator: "\n")
Issue.record(message, sourceLocation: sourceLocation)
}
}
// Penggunaan dalam test
@Test("User creation sets all properties correctly")
func userCreation() {
let user = User(name: "Ari", age: 28, email: "ari@example.com", isActive: true)
// Assert banyak properti sekaligus, semua type-safe
assertAll("User properties",
pairs:
(actual: user.name, expected: "Ari"),
(actual: user.age, expected: 28),
(actual: user.email, expected: "ari@example.com"),
(actual: user.isActive, expected: true)
)
// Jika beberapa gagal, semua failure dilaporkan sekaligus
}
struct User {
var name: String
var age: Int
var email: String
var isActive: Bool
}