Created
September 21, 2019 15:12
-
-
Save chchrn/0eff4681bf1f9f5312ce7b862c168cc8 to your computer and use it in GitHub Desktop.
Gist for question: https://stackoverflow.com/questions/57944086/how-to-use-a-variable-that-conforms-to-a-protocol-with-a-specific-associated-typ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
// For my question about abstract mapping: https://stackoverflow.com/questions/57944086/how-to-use-a-variable-that-conforms-to-a-protocol-with-a-specific-associated-typ | |
// Abstract mapping | |
protocol Mapping { | |
associatedtype T | |
associatedtype R | |
func map(_ object:T) -> R | |
} | |
class AbstractMapping<TModel,TResult>: Mapping { | |
typealias T = TModel | |
typealias R = TResult | |
func map(_ object: TModel) -> TResult { | |
fatalError("map(_:) has not been implemented") | |
} | |
} | |
class ClosureMapping<TModel,TResult>: AbstractMapping<TModel,TResult> { | |
typealias Closure = (TModel) -> TResult | |
private let closure: Closure | |
init(closure: @escaping Closure) { | |
self.closure = closure | |
} | |
override func map(_ obj: TModel) -> TResult { | |
return self.closure(obj) | |
} | |
} | |
class Calculator<TMapping: Mapping, TModel, TResult: Numeric> where TMapping.T == TModel, TMapping.R == TResult { | |
private let mapping: TMapping | |
init(mapping: TMapping) { | |
self.mapping = mapping | |
} | |
func calc(objects: [TModel]) -> TResult { | |
let numbers = objects.map { (v: TModel) -> TResult in | |
return self.mapping.map(v) | |
} | |
let sum = numbers.reduce(0, +) | |
return sum | |
} | |
} | |
// User | |
class User { | |
private let purchase: Double | |
private let name: String | |
init(name: String, purchase: Double) { | |
self.name = name | |
self.purchase = purchase | |
} | |
func yearPurchases() -> Double { | |
return self.purchase * 12 | |
} | |
func monthPurchases() -> Double { | |
return self.purchase | |
} | |
} | |
// User's mapping | |
class UserMonthPurchaseMapping: AbstractMapping<User,Double> { | |
override func map(_ user: User) -> Double { | |
return user.monthPurchases() | |
} | |
} | |
// Specific use of two types of mapping | |
typealias UserClosureMapping = ClosureMapping<User,Double> | |
let yearPurchaseMapping = UserClosureMapping { (user: User) -> Double in | |
user.yearPurchases() | |
} | |
let monthPurchaseMapping = UserMonthPurchaseMapping() | |
let yearCalc: Calculator<AbstractMapping<User,Double>, User, Double> = Calculator(mapping: yearPurchaseMapping) | |
let monthCalc: Calculator<AbstractMapping<User,Double>, User, Double> = Calculator(mapping: monthPurchaseMapping) | |
let users = [User(name: "1", purchase: 10), User(name:"2", purchase:20), User(name:"3", purchase:5)] | |
let sumYear = yearCalc.calc(objects: users) | |
let sumMonth = monthCalc.calc(objects: users) | |
print("sumYear: \(sumYear), sumMonth: \(sumMonth)") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment