如何创建包含属于特定类的对象的数组。
class BaseObject {}
class Derived1: BaseObject {}
class Derived2: BaseObject {}
class Derived2: BaseObject {}
我需要创建一个数组,其中只包含从BaseObject
类似于 - var array : [BaseObject.Type] = []
有没有办法指定这个?
另外,我应该可以使用类似这样的东西
if let derived1 = object as? [Derived1] {
}
else if let derived2 = object as? [Derived2] {
}
答案 0 :(得分:1)
显然,您可以将数组定义为BaseObject
:
var objects: [BaseObject] = [] // or `var objects = [BaseObject]()`
但它可以让你创建一个异类集合(BaseObject
或Derived1
或Derived2
或任何其他子类。这是一个核心的OO设计概念(Liskov substitution principle),BaseObject
的任何子类都应该(并且将被允许)。
如果您想要的只是说您只能拥有其中一个子类型的数组,那么显然可以直接定义您的数组,例如:
var objects: [Derived1] = []
这显然只允许Derived1
个对象(以及Derived1
的任何子类。
最重要的是,我们应该进行子类化,还是应该使用面向协议的方法?即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
方法,可以使用符合此协议的所有类型,例如Object1
,Object2
等,而无需实现foo
他们自己(当然,除非你因为出于某种原因他们需要特殊行为)。
因为这消除了子类化,这为使用泛型和协议打开了大门,这些泛型和协议规定了一些广义的行为,同时规定了成员的同质性。例如:
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()
现在,我只是走这条路,因为在其他地方的评论中,你在询问仿制药。如果(a)集合真的需要是同质的,我个人只会走这条路。 (b)该集合还希望实现协议共有的一些共享逻辑。否则,我可能会坚持使用简单的[Derived1]
(或[Object1]
)。以上在需要时可以很强大,但对于更简单的情况来说是过度的。
关于面向协议编程的更多讨论,同质与异类行为,当你来自传统的OO思维模式时,传统的绊脚石,我会推荐你参加WWDC 2015视频,Protocol-Oriented Programming in Swift,或者它2016 companion video以2015年视频为基础。
最后,如果您有任何其他问题,我建议您编辑您的问题,提供您尝试使用此模式解决的实际问题的详细信息。抽象的讨论往往没有成效。但是,如果你告诉我们你试图用你的问题中的模式解决的实际问题是什么,那将是一个更具建设性的对话。