Swift 有类似的东西:协议扩展
他们可以定义默认实现,因此您不必在基类中声明该方法,但它也不会强制在任何类、结构或枚举中这样做。
protocol P {
associatedtype TypeParameter
func A()
func B()
}
extension P {
func A(){}
}
class BaseClass<TypeParam> : P {
typealias TypeParameter = TypeParam
func B(){
if someCondition {
A()
}
}
}
class ChildClass : BaseClass<Int> {
// implementation of A() is not forced since it has a default implementation
func A(){}
}
另一种方法是使用协议而不是BaseClass
更符合面向协议的编程:
protocol Base {
associatedtype TypeParameter
func A()
func B()
}
extension Base {
func B(){
if someCondition {
A()
}
}
}
class ChildClass : Base {
typealias TypeParameter = Int
// implementation of A() is forced but B() is not forced
func A(){}
}
然而,最大的缺点之一是协议类型的变量只能在泛型代码中使用(作为泛型约束):
var base: Base = ChildClass() // DISALLOWED in every scope
作为此限制的解决方法,您可以创建一个包装器类型:
// wrapper type
struct AnyBase<T>: Base {
typealias TypeParameter = T
let a: () -> ()
let b: () -> ()
init<B: Base>(_ base: B) where B.TypeParameter == T {
// methods are passed by reference and could lead to reference cycles
// below is a more sophisticated way to solve also this problem
a = base.A
b = base.B
}
func A() { a() }
func B() { b() }
}
// using the wrapper:
var base = AnyBase(ChildClass()) // is of type AnyBase<Int>
关于“真正的”泛型协议的使用,Swift 团队选择使用associatedtype
,因为您可以使用许多泛型类型,而不必全部写在括号中<>
。
例如Collection
,您有关联Iterator
和Index
类型。这允许您拥有特定的迭代器(例如 forDictionary
和Array
)。
一般来说,泛型/关联类型有利于编译期间的代码优化,但同时有时过于静态,您必须使用泛型包装器类型。
一些使用关联类型的模式的有用链接。
(另见上文)
一种更复杂的方法来解决通过引用传递方法的问题。
// same as `Base` but without any associated types
protocol _Base {
func A()
func B()
}
// used to store the concrete type
// or if possible let `Base` inherit from `_Base`
// (Note: `extension Base: _Base {}` is currently not possible)
struct BaseBox<B: Base>: _Base {
var base: B
init(_ b: B) { base = b}
func A() { base.A() }
func B() { base.B() }
}
struct AnyBase2<T>: Base {
typealias TypeParameter = T
var base: _Base
init<B: Base>(_ base: B) where B.TypeParameter == T {
self.base = BaseBox(base)
}
func A() { base.A() }
func B() { base.B() }
}
// using the wrapper:
var base2 = AnyBase2(ChildClass()) // is of type AnyBase2<Int>