2

我是一个快速的初学者。学习的时候有一点让我困惑。现在我想定义一个抽象类或定义一些纯虚方法,但我找不到办法。我有一个带有关联类型的协议(这也让我很困惑,为什么不使用泛型协议),有些方法需要在基类中实现,而其他类继承自基类,它们应该在协议中实现其他方法,我能怎么做?例如:

Ptotocol P{
    typealias TypeParam
    func A()
    func B()
}

class BaseClass<TypeParam> : P {
    abstract func A()
    func B(){
        if someCondition {
            A()
        }
    }
}

class ChildClass : BaseClass<Int> {
    func A(){}
}

看起来很奇怪,我仍然找不到解决抽象问题的方法。

4

1 回答 1

4

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,您有关联IteratorIndex类型。这允许您拥有特定的迭代器(例如 forDictionaryArray)。

一般来说,泛型/关联类型有利于编译期间的代码优化,但同时有时过于静态,您必须使用泛型包装器类型。

一些使用关联类型的模式的有用链接。


(另见上文)

一种更复杂的方法来解决通过引用传递方法的问题。

// 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>
于 2015-10-13T11:39:42.383 回答