Swift - 具有特定类类型的数组

时间:2017-10-16 03:10:11

标签: arrays swift

如何创建包含属于特定类的对象的数组。

class BaseObject {}

class Derived1: BaseObject {}
class Derived2: BaseObject {}
class Derived2: BaseObject {}

我需要创建一个数组,其中只包含从BaseObject

派生的Object

类似于 - var array : [BaseObject.Type] = []

有没有办法指定这个?

另外,我应该可以使用类似这样的东西

if let derived1 = object as? [Derived1] {

}
else if let derived2 = object as? [Derived2] {

}

1 个答案:

答案 0 :(得分:1)

显然,您可以将数组定义为BaseObject

的数组
var objects: [BaseObject] = []  // or `var objects = [BaseObject]()`

但它可以让你创建一个异类集合(BaseObjectDerived1Derived2或任何其他子类。这是一个核心的OO设计概念(Liskov substitution principle),BaseObject的任何子类都应该(并且将被允许)。

如果您想要的只是说您只能拥有其中一个子类型的数组,那么显然可以直接定义您的数组,例如:

var objects: [Derived1] = []

这显然只允许Derived1个对象(以及Derived1的任何子类。

90%的时间,以上就足够了。但在某些情况下,您可能需要使用需要某些继承基本行为的方法进行某些集合,但您不希望允许异构集合。在这种情况下,我可能会考虑更加面向协议的模式:

  1. 最重要的是,我们应该进行子类化,还是应该使用面向协议的方法?即BaseObject实际上是为了自己的目的而实例化的东西,或仅仅是为了定义子类的一些常见行为。如果是后者,协议可能是更好的模式,例如:

    protocol Fooable {
        func foo()
    }
    
    // if you want, provide some default implementation for `foo` in an
    // protocol extension
    
    extension Fooable {
        func foo() {
            // does something unique to objects that conform to this protocol
        }
    }
    
    struct Object1: Fooable {}
    struct Object2: Fooable {}
    struct Object3: Fooable {}
    

    这会产生您可能在更多面向对象方法中使用的行为,但使用协议。具体来说,您编写了一个foo方法,可以使用符合此协议的所有类型,例如Object1Object2等,而无需实现foo他们自己(当然,除非你因为出于某种原因他们需要特殊行为)。

  2. 因为这消除了子类化,这为使用泛型和协议打开了大门,这些泛型和协议规定了一些广义的行为,同时规定了成员的同质性。例如:

    struct FooCollection<T: Fooable> {
        private var array = [T]()
    
        mutating func append(_ object: T) {
            array.append(object)
        }
    
        // and let's assume you need some method for your collection that
        // performs some `Fooable` task for each instance
    
        func fooAll() {
            array.forEach { $0.foo() }
        }
    }
    

    这是一个通用的,它是符合您协议的同类对象集合。例如,当您去使用它时,您将声明要使用的特定类型的Fooable类型:

    var foo = FooCollection<Object1>()
    
    foo.append(Object1())  // permitted
    foo.append(Object2())  // not permitted
    
    foo.fooAll()
    
  3. 现在,我只是走这条路,因为在其他地方的评论中,你在询问仿制药。如果(a)集合真的需要是同质的,我个人只会走这条路。 (b)该集合还希望实现协议共有的一些共享逻辑。否则,我可能会坚持使用简单的[Derived1](或[Object1])。以上在需要时可以很强大,但对于更简单的情况来说是过度的。

    关于面向协议编程的更多讨论,同质与异类行为,当你来自传统的OO思维模式时,传统的绊脚石,我会推荐你​​参加WWDC 2015视频,Protocol-Oriented Programming in Swift,或者它2016 companion video以2015年视频为基础。

    最后,如果您有任何其他问题,我建议您编辑您的问题,提供您尝试使用此模式解决的实际问题的详细信息。抽象的讨论往往没有成效。但是,如果你告诉我们你试图用你的问题中的模式解决的实际问题是什么,那将是一个更具建设性的对话。