Общий экземпляр по наследству - PullRequest
0 голосов
/ 20 апреля 2020

Скажем, инфраструктура предоставляет настраиваемые сервисы через open class A, который предоставляет совместно используемый экземпляр для использования следующим образом:

open class A {
    public static let shared = A()
    open func aService() {} 
}

Обычное использование сервиса следующее:

A.shared.aService()

Важное примечание: сам общий экземпляр также используется из кода class A или связанного кода в Framework.

Допустим, вы хотите настроить службу с помощью наследования, и вы все еще хотите сохранить использование общего экземпляра следующим образом:

override class B: A {
    public override func aService() {
        super.aService()
    } 
}

Когда вы, к сожалению, обращаетесь к общему экземпляру, он ссылается на экземпляр class A, где вы хотите, чтобы он ссылался на экземпляр унаследованного класса.

B.shared.aService() // Failed!: This actually calls A.shared.aService()

Один из способов исправить это сделать конструкцию следующим образом:

class A {
    public static var shared = A()
}

Тогда перед любым использованием службы в вашем приложении вы уверены, что измените экземпляр следующим образом:

A.shared = B()
B.shared.aService() // OK! This actually calls B.aService()

Хотя все это работает, я хотел бы сделать его автоматическим c, а не полагаться в начальной строке, которая изменяет общий экземпляр.

Как бы вы это сделали?

[КОД ДЛЯ ВОСПРОИЗВЕДЕНИЯ] , который иллюстрирует цель достижения и помогает вам лучше понять вопрос

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)

1 Ответ

1 голос
/ 20 апреля 2020

Есть решение, но ...

Лично я согласен с другими комментариями здесь. Это на самом деле не похоже на работу для одноэлементного паттерна.

В вашем текущем решении вы, кажется, совершенно счастливы перезаписать промежуточное исполнение экземпляра синглтона, что означает, что это не синглтон. Предполагается, что существует только один экземпляр синглтона, и если вы можете непрерывно создавать и назначать новый экземпляр переменной shared, ничего не нарушая, то просто не нужно иметь это глобальное состояние в вашем приложении.

Однако, для записи, вы можете достичь того, что вы хотите, с помощью struct, который составляет stati c экземпляров каждого класса и который может обнаружить вызывающий контекст и вернуть соответствующий. каждый раз, когда к 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

Итак, да, вы можете достичь того, что вы хотите. Но есть довольно веские основания утверждать, что вы не должны ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...