Swift 共享实例访问继承

Swift 共享实例访问继承,swift,inheritance,Swift,Inheritance,假设一个框架通过一个开放的类a提供可定制的服务,该类公开了一个共享实例以供使用,如下所示: open class A { public static let shared = A() open func aService() {} } A.shared.aService() override class B: A { public override func aService() { super.aService() } } class

假设一个框架通过一个开放的
类a
提供可定制的服务,该类公开了一个共享实例以供使用,如下所示:

open class A {
    public static let shared = A()
    open func aService() {} 
}
A.shared.aService()
override class B: A {
    public override func aService() {
        super.aService()
    } 
}
class A {
    public static var shared = A()
}
A.shared = B()
B.shared.aService() // OK! This actually calls B.aService()
该服务的常规使用情况如下:

open class A {
    public static let shared = A()
    open func aService() {} 
}
A.shared.aService()
override class B: A {
    public override func aService() {
        super.aService()
    } 
}
class A {
    public static var shared = A()
}
A.shared = B()
B.shared.aService() // OK! This actually calls B.aService()
重要注意事项:共享实例本身也在
A类
代码或框架中的相关代码中使用

假设您希望通过继承来定制服务,但仍然希望按如下方式保持对共享实例的使用:

open class A {
    public static let shared = A()
    open func aService() {} 
}
A.shared.aService()
override class B: A {
    public override func aService() {
        super.aService()
    } 
}
class A {
    public static var shared = A()
}
A.shared = B()
B.shared.aService() // OK! This actually calls B.aService()
不幸的是,当您引用共享实例时,它引用的是
类A
实例,您希望它引用的是继承的类实例

B.shared.aService() // Failed!: This actually calls A.shared.aService()
解决此问题的一种方法是按如下方式进行构造:

open class A {
    public static let shared = A()
    open func aService() {} 
}
A.shared.aService()
override class B: A {
    public override func aService() {
        super.aService()
    } 
}
class A {
    public static var shared = A()
}
A.shared = B()
B.shared.aService() // OK! This actually calls B.aService()
然后,在使用应用程序中的任何服务之前,请确保按以下方式更改实例:

open class A {
    public static let shared = A()
    open func aService() {} 
}
A.shared.aService()
override class B: A {
    public override func aService() {
        super.aService()
    } 
}
class A {
    public static var shared = A()
}
A.shared = B()
B.shared.aService() // OK! This actually calls B.aService()
虽然整个过程都是有效的,但我希望它是自动的,而不是依赖于更改共享实例的初始行

B.shared.aService() // Failed!: This actually calls A.shared.aService()
你会怎么做

[操场代码]说明要实现的目标,并帮助您更好地理解问题

open class A {
    public static var shared = A()
    open func aService() {
        print("\(type(of: self)): service (from A)")
    }

}

class B: A {
    public override func aService() {
        super.aService()
        print("\(type(of: self)): service (from B)")
    }
}

A.shared = B()          // Question : How to remove the need to this line, yet achieving the same functionality (and output)

A.shared.aService()
B.shared.aService()

// The output (which is correct) :
//B: service (from A)
//B: service (from B)
//B: service (from A)
//B: service (from B)

有一个解决办法,但是

我个人同意这里的其他评论。这听起来真的不像是针对单身模式的工作

在当前的解决方案中,您似乎非常乐意在执行期间覆盖singleton实例,这意味着它不是singleton。假设一个单例只有一个实例,如果您可以连续创建一个新实例并将其分配给
shared
变量,而不破坏任何内容,那么您的应用程序中就不必有这种全局状态

但是,对于记录,您可以使用构成每个类的静态实例的
struct
实现所需的功能,该结构可以检测调用上下文,并在每次访问
shared
时返回相应的上下文:

protocol ExampleProtocol {
    static var shared: ExampleProtocol { get }
    func service()
}

struct ExampleProvider {
    private static var a = A()
    private static var b = B()
    static func instance(type: ExampleProtocol.Type) -> ExampleProtocol {
        return type == A.self ? ExampleProvider.a : ExampleProvider.b
    }
}

class A: ExampleProtocol {
    static var shared: ExampleProtocol {
        return ExampleProvider.instance(type: Self.self)
    }
    func service() {
        print("Hello")
    }
}

class B: A {
    override func service() {
        print("Goodbye")
    }
}

A.shared.service() // Hello
B.shared.service() // Goodbye

所以,是的,你可以实现你想要的。但是有一个非常有力的理由说你不应该…。

这不是答案,但a类应该被宣布为最终等级,所以它不能被扩展。我希望A可以通过继承进行扩展1)如果可能,不要对扩展点使用继承。如果您只需要在某些事情发生时得到通知,请使用Observable。如果希望能够完全更改方法的实现,请使用委托模式。2) 可以有一个是final类和一个singleton,其中包含
InnerA
A
将所有操作委托给
InnerA
,InnerA本身是子类化的。当创建子类时,您可以用新的
InnerB
替换
a
中的备份实例,但仍然只有一个
a
实例,因此这对世界其他地方来说是透明的,听起来像是一个依赖注入的工作。不是单身,同意;你在这里描述的不是继承。只是全局变量碰巧是通过静态命名的。这不是提供自定义点的适当方式。Swift提供了许多更好的解决方案(如上所述)。委托或传递闭包。“类似继承”的解决方案将是脆弱的,因为它不是继承。这并没有回答问题:在您的示例中,两者都应该返回再见。另外,与我的问题相比,这是大量的代码。在我的示例中,这两个代码都不会返回“再见”。运行它。你的问题没有答案。由于其本质,您无法覆盖静态的内容。这就像问为什么我的车不能飞,即使我已经安装了机翼。。。你想做一些完全荒谬的事。在我的示例中可能有更多的代码,但是使用接口将客户机与单例类分离,这大大超过了您对大量依赖项的偏好。