我有一个以这种格式构建的相当大的项目:
class One : FirstThree {
fileprivate var integers: [Int] {
return [1, 2, 3, 101, 102]
}
override func allIntegers() -> [Int] {
return integers
}
func doStuffForOne() {
//does stuff unrelated to the other classes
}
}
class Two : FirstThree {
fileprivate var integers: [Int] {
return [1, 2, 3, 201]
}
override func allIntegers() -> [Int] {
return integers
}
func doStuffForTwo() {
//does stuff unrelated to the other classes
}
}
class Three : Numbers {
fileprivate var integers: [Int] {
return [301, 302, 303]
}
override func allIntegers() -> [Int] {
return integers
}
func doStuffForThree() {
//does stuff unrelated to the other classes
}
}
class FirstThree : Numbers {
fileprivate var integers: [Int] {
return [1, 2, 3]
}
override func allIntegers() -> [Int] {
return integers
}
func doStuffForFirstThree() {
//does stuff unrelated to the other classes
}
}
class Numbers {
func allIntegers() -> [Int] {
fatalError("subclass this")
}
func printMe() {
allIntegers().forEach({ print($0) })
}
}
Numbers
有许多方法,例如printMe()
,我希望所有子类的任何实例都可以调用。
Numbers
还有一个allIntegers()
函数,我希望这些子类的任何实例都能够调用。作为一个变量,这可能会更好吗?但我无法覆盖子类中的变量。因此,我在每个子类中使用相同的私有变量integers
,由allIntegers()
读取并返回。
另请注意Numbers
本身的实例永远不应该调用allIntegers()
,只应在子类上调用它。
最后,请注意一些子类包含相同的对象1, 2, 3
,然后每个子类都有一些自定义整数。但不是所有的子类。如果我后来决定所有这些子类需要一个4
整数,我必须手动遍历每个类并在4
中插入数组,这显然容易出错。
我已经阅读过面向协议的编程,感觉解决方案可能就在那里,或者我感谢任何其他建议和创造性方法来构建更好的项目。
谢谢!
修改
所有子类都不同,因为它们也有自己的功能。我已更新代码以反映这一点。
想象一下,像One
这样的给定类在整个代码库中被多次初始化,并且始终使用完全相同的integers
进行初始化。把:
let one = One(integers: [1, 2, 3, 101, 102])
整个代码库中的所有内容都容易出错。
希望这能解决我提出的人为设想的一些问题。
解
谢谢大家的帮助。这是我提出的解决方案(请假设所有类都有自己独特的方法)。
class One : FirstThree {
override init() {
super.init()
self.integers = super.integers + [101, 102]
}
}
class Two : FirstThree {
override init() {
super.init()
self.integers = super.integers + [201]
}
}
class Three : Numbers {
var integers = [301, 302, 303]
}
class FirstThree : Numbers {
let integers = [1, 2, 3]
}
protocol Numbers {
var integers: [Int] { get }
func printMe()
}
extension Numbers {
func printMe() {
integers.forEach({ print($0) })
}
}
答案 0 :(得分:4)
根据您在问题中添加的新信息,这是一种可行的方法
我真的无法抗拒所以我稍微重构了命名:D
现在你有一个协议
protocol HasIntegers {
var integers: [Int] { get }
func printMe()
}
和添加printMe函数的协议扩展。
extension HasIntegers {
func printMe() {
integers.forEach { print($0) }
}
}
最后你有2个类(代码中有4个类但想法没有改变)。
A类总是包含[1, 2, 3, 101, 102]
并拥有自己的方法集(doSomething()
)
class A: HasIntegers {
fileprivate (set) var integers: [Int] = [1, 2, 3, 101, 102]
func doSomething() { }
}
班级B
始终包含[1,2,3,201],并且有一套不同的方法(doSomethingElse()
)
class B: HasIntegers {
fileprivate (set) var integers: [Int] = [1, 2, 3, 201]
func doSomethingElse() { }
}
A和B都符合HasInteger,然后自动接收printMe()
方法。
老答案
我在你的代码中看到很多东西:
但是没有明显的理由使用所有这些东西:)
class Box {
fileprivate (set) var integers: [Int]
init(integers:[Int]) {
self.integers = integers
}
func printMe() {
integers.forEach { print($0) }
}
}
let one = Box(integers: [1, 2, 3, 101, 102])
let two = Box(integers: [1, 2, 3, 201])
let three = Box(integers: [1, 2, 3, 301, 302, 303])
let four = Box(integers: [401, 402])
答案 1 :(得分:2)
使用常用操作定义协议,包括objects
访问者:
protocol Numbers {
/// My objects. By default, `Numbers.commonObjects`. Subclasses can override to include more objects.
var objects: [Int] { get }
func printMeThatConformersCanOverride()
}
在扩展程序中提供默认实现:
extension Numbers {
/// The default implementation of `objects`, which just returns `Numbers_defaultObjects`.
var objects: [Int] { return Numbers_defaultObjects }
/// Since this is declared in the protocol, conformers can override it.
func printMeThatConformersCanOverride() {
Swift.print("Numbers " + objects.map({ "\($0)" }).joined(separator: " "))
}
}
/// It would be nice to make this a member of `Numbers`, but Swift won't let us.
private let Numbers_defaultObjects = [1, 2, 3]
因为这些定义实现了协议中声明的内容,所以符合类型可以覆盖它们。您还可以在扩展中定义符合类型无法覆盖的内容:
extension Numbers {
/// Since this is not declared in the protocol, conformers cannot override it. If you have a value of type `Numbers` and you call this method on it, you get this version.
func printMeThatConformersCannotOverride() {
Swift.print("Numbers " + objects.map({ "\($0)" }).joined(separator: " "))
}
}
然后我们可以实现符合协议的类。我们可以使用let
覆盖objects
:
class One: Numbers {
/// You can use a `let` to override `objects`.
let objects: [Int] = Numbers_defaultObjects + [101, 102]
func doStuffForOne() {
Swift.print("I'm doing One-specific stuff with \(objects)")
}
func printMeThatConformersCanOverride() {
Swift.print("One wins! You don't care what type I am.")
}
func printMeThatConformersCannotOverride() {
Swift.print("One wins! You think I'm type One, not type Numbers.")
}
}
我们可以使用存储的属性来覆盖objects
:
class Two: Numbers {
/// You can use a stored property to override `objects`.
var objects: [Int] = Numbers_defaultObjects + [201]
func doStuffForTwo() {
Swift.print("I'm doing Two-specific stuff with \(objects)")
}
}
我们可以使用计算属性来覆盖objects
:
class Three: Numbers {
/// You can use a computed property to override `objects`.
var objects: [Int] { return [301, 302, Int(arc4random())] }
func doStuffForThree() {
Swift.print("I'm doing Three-specific stuff with \(objects)")
}
}
我们甚至不必使用类类型。我们可以使用结构类型:
struct Four: Numbers {
func doStuffForFour() {
Swift.print("I'm doing Four-specific stuff with \(objects)")
}
}
我上面说过,你可以在扩展中定义东西,如果它们没有在协议中声明,那么符合类型不能覆盖它们。这在实践中可能有点混乱。如果尝试像One
那样尝试覆盖扩展中定义但不属于协议的方法,会发生什么?
let one = One()
one.printMeThatConformersCanOverride()
// output: One wins! You don't care what type I am.
(one as Numbers).printMeThatConformersCanOverride()
// output: One wins! You don't care what type I am.
one.printMeThatConformersCannotOverride()
// output: One wins! You think I'm type One, not type Numbers.
(one as Numbers).printMeThatConformersCannotOverride()
// output: Numbers 1 2 3 101 102
对于协议中声明的方法,运行属于值的运行时类型的版本。对于未在协议中声明的方法,运行属于该值的编译时类型的版本。
答案 2 :(得分:1)
我假设你有一个非常复杂的应用程序,这些带有一些虚函数的简单类只是一个简单的例子。所以这是一种使用协议重构的方法:
第一步可以将Numbers
基类更改为具有默认实现的协议,如:
class One : Numbers {
fileprivate var _objects: [Int] {
return [1, 2, 3, 101, 102]
}
func objects() -> [Int] {
return _objects
}
}
class Two : Numbers {
fileprivate var _objects: [Int] {
return [1, 2, 3, 201]
}
func objects() -> [Int] {
return _objects
}
}
class Three : Numbers {
fileprivate var _objects: [Int] {
return [1, 2, 3, 301, 302, 303]
}
func objects() -> [Int] {
return _objects
}
}
class Four : Numbers {
fileprivate var _objects: [Int] {
return [401, 402]
}
func objects() -> [Int] {
return _objects
}
}
protocol Numbers {
func objects() -> [Int];
func printMe() ;
}
//Default implementation of the services of Numbers.
extension Numbers {
func objects() -> [Int] {
fatalError("subclass this")
}
func printMe() {
objects().forEach({ print($0) })
}
}
然后让我们从objects()
创建一个变量,正如您在问题中所说的那样(在这种情况下objects
是只读的,您无法在实例中更新它):
class One : Numbers {
//Protocol specifying only the getter, so it can be both `let` and `var` depending on whether you want to mutate it later or not :
let objects = [1, 2, 3, 101, 102]
}
class Two : Numbers {
var objects = [1, 2, 3, 201]
}
class Three : Numbers {
var objects = [1, 2, 3, 301, 302, 303]
}
class Four : Numbers {
let objects = [401, 402]
}
protocol Numbers {
var objects:[Int] { get }
func printMe() ;
}
//Default implementation of the services of Numbers.
extension Numbers {
func printMe() {
objects.forEach({ print($0) })
}
}
如果objects
可以是只读的,您仍然可以为objects
getter添加默认实现,例如:
class Four : Numbers {
}
protocol Numbers {
var objects:[Int] { get }
func printMe() ;
}
//Default implementation of the services of Numbers.
extension Numbers {
var objects: [Int] {
return [401, 402]
}
func printMe() {
objects.forEach({ print($0) })
}
}