Связывание протоколов со связанными объектами - протоколно-ориентированное программирование с Swift - PullRequest
0 голосов
/ 06 октября 2018

Я разработчик iOS с парой опыта работы в swift, но редко использую PAT ...

На этот раз я пытался переместить некоторый код из приложения, которое яЯ разработал для общей библиотеки, которую я использую в нескольких проектах.В данном случае речь идет о фабрике, которая использует различные Builders (которые являются декораторами моих бизнес-ресурсов) через протокол Abstract Builder для получения элементов (в реальном случае ViewControllers).

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

// The item that i want to receive from my factory
protocol Item { 
    var content: String { get }
}

// This is the Builder interface that the Factory consumes
protocol Builder {  

    // The Abstract Parameters that the Application should define
    associatedtype Parameters

    func build(_ parameters: Parameters) -> Item?
}

// The BusinessResource of my library 
protocol BusinessResource { }

// The Factory that consumes the Builders
protocol Factory {

    associatedtype FactoryBuilder: Builder

    var parameters: FactoryBuilder.Parameters { get }

    func make(from businessResource: BusinessResource) -> Item?
}

// The generic implementation of my Factory
extension Factory {

    func make(from businessResource: BusinessResource) -> Item? {

        guard let builder = businessResource as? FactoryBuilder else {
            return nil
        }
        return builder.build(self.parameters)
    }
}

На данный момент все выглядит хорошо.

У меня есть два протокола, и они связаны между собой, разделяя общий тип, который является общим (параметры построителя).

Итак, на прикладном уровне теперь я могу представить свои конкретные параметры (я буду называть их ConcreteParameters XD)

// The concrete parameters of the Application Factory
struct ConcreteParameters {
    let string: String
}

// The Builder interface restricting Parameters to ConcreteParameters 
protocol BindedBuilder: Builder where Parameters == ConcreteParameters {

}

// The Factory interface restricting Parameters to ConcreteParameters 
protocol BindedFactory: AbstractFactory where FactoryParameters: ConcreteParameters {

}

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

// The concrete output of my Builder
struct ConcreteItem: Item {
    var content: String
}

// The concrete BusinessResource that i get from my library
struct ConcreteObject: BusinessResource {

    let string: String
}

// The decoration extension that makes ConcreteObject compliant with Builder
extension ConcreteObject: Builder {

    typealias Parameters = ConcreteParameters

    func build(_ parameters: ConcreteParameters) -> Item? {
        return ConcreteItem(content: parameters.string + self.string)
    }
}

// The real Factory inside my app
class ConcreteFactory: BindedFactory {

    typealias FactoryBuilder = BindedBuilder

    var parameters: ConcreteParameters {
        return ConcreteParameters(string: "Hello ")
    }
}

let item = ConcreteFactory().make(from: ConcreteObject(string: "world!"))
print(item ?? "NOT WORKING")

В этот момент что-то ломается ..Я получаю эту ошибку:

Error: Type ConcreteFactory does not conform to AbstractFactory

[ EDIT : ошибка возникла в предыдущей версии фрагмента, AbstractFactoriэто Фабрика ]

Это ошибка ??Я действительно не знаю, как решить это ...

1 Ответ

0 голосов
/ 11 октября 2018

Я думаю, что в этом случае вам нужно использовать конкретный тип для псевдонима FactoryBuilder вместо BindedBuilder, так как протоколы не соответствуют себе .

Этот код эффективно компилируетсябудет ли что-то подобное соответствовать вашим требованиям?

class ConcreteFactory: BindedFactory {
    typealias FactoryBuilder = ConcreteObject

    var parameters: ConcreteParameters {
        return ConcreteParameters(string: "Hello ")
    }
}

В противном случае вы также можете попробовать стереть BindedBuilder и создать AnyBindedBuilder, как предлагается в той же ссылке.

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