Создать фабрику стилей на основе протокола - PullRequest
1 голос
/ 09 октября 2019

Фон

У меня есть приложение, которое взаимодействует с рядом аппаратных устройств. Все эти устройства имеют некоторые базовые функциональные возможности, но они также могут иметь 0 или более «возможностей» (помимо их базовой функциональности).

В настоящее время существует что-то вроде 30+ «других» возможностей, которые эти устройства могут"иметь

Кроме того, чтобы усложнить проблему, реализация возможностей на одном устройстве не одинакова на другом устройстве (мир просто так не работает ?)

Проблема

Я пытаюсь разработать решение API, которое позволило бы мне более легко управлять этим разнообразным набором функций.

Первоначально я пытался создать protocol для каждой возможности. и затем приведите каждую реализацию устройства в соответствие с этими protocol s.

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

Кроме того, чтобы приложение могло определить,У устройства есть возможность, мне нужно использовать if instance is capable и if let capability = instance as? Capability, где угодно, что не всегда красиво или не всегда практично.

Некоторые возможности изменчивы, и приведенное выше просто не вызывает никаких предупреждений компилятора.

Есть и другие недостатки, которые требуют от меня компрометации дизайна, например, чтобы уменьшить количество реальных классов, я должен был включить опции «действительно поддерживает» во многих извозможности, как экземпляр устройства «может» поддерживать возможность, но не знаю, пока я не интегрирую устройство во время выполнения.

«A» решение

Затем я подумал, что яочень хотелось бы сделать, это изолировать функциональность возможностей в их собственных объектах, отделить их от самих базовых устройств, чтобы я мог «попросить» устройствоэкземпляр возможности, и если бы он был способен поддерживать его, он бы возвратил экземпляр, в противном случае он вернул бы nil

Что-то вроде:

if let capability = device.capability(for: Capabilities.toggableSetting) {...}

Желание было быиспользовать enum для представления поддерживаемых возможностей, поскольку это становится самодокументируемым, самопроверкаемым, легко читаемым и понятным.

С этой целью я пришел к очень быстрой идее, которая выглядела примерно как

protocol Capability { }

protocol ToggableSetting: Capability {
    func set(value: String) //{}
}

enum Capabilities {
    case toggableSetting
}

protocol Device {
    func capability<T: Capability>(for capability: Capabilities) -> T?
}

class SomeImplementationOfToggableSetting: ToggableSetting {
    func set(value: String) {
        // NOOP
    }
}

class SomeDevice: Device {

    let toggableSetting = SomeImplementationOfToggableSetting()

    func capability<T>(for capability: Capabilities) -> T? where T : Capability {
        switch capability {
        case .toggableSetting: return toggableSetting as? T
        }
        return nil
    }

}

let test = SomeDevice()
let ts: ToggableSetting? = test.capability(for: .toggableSetting)
ts

Как некоторые из вас сразу увидят, это не будет работать, так как это приведет к

Тип протокола 'ToggableSetting' не может соответствовать 'Capability', потому что только конкретные типыможет соответствовать протоколам

при let ts: ToggableSetting? = test.capability(for: .toggableSetting)

Итак, после некоторого прочтения и исследования, у меня появилась идея ввести «базовый» класс ...

class AnyToggableSetting: ToggableSetting {
    func set(value: String) { fatalError("Not yet implemented") }
}

Что нужно реализовать ...

class SomeImplementationOfToggableSetting: AnyToggableSetting {
    override func set(value: String) {
        // NOOP
    }
}

И тогда я мог бы использовать что-то вроде ...

let ts: AnyToggableSetting? = test.capability(for: .toggableSetting)

Хорошо, это работает, ноне так чисто, как хотелось бы.

хотелось бычтобы максимально разделить реализацию и работать с protocol, поэтому мой код говорит: «Я хочу что-то, что подтверждает тоже, сказанное protocol», и «не то, что ДОЛЖНО расширяться от AnySomething»

Есть другие проблемы с дизайном, которые я хотел бы избежать, если это возможно (свойства не наследуются, например)

«Вопрос»

Итак, основной вопрос в том,есть ли способ, которым я могу использовать этот стиль "фабрики", чтобы я мог получить protocol по сравнению с необходимостью предоставления подставки Any в объекте?

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