Заводская модель с различными протоколами в Swift - PullRequest
0 голосов
/ 02 февраля 2019

Я пытаюсь использовать фабричный шаблон в swift, и дать мой код

У меня есть два протокола

protocol MyProtocol1{
    func callLoginAPI()
}

protocol MyProtocol2{
    func callPaymentAPI()
}

У меня есть две структуры, которые соответствуют этим протоколам

struct MyManager1: MyProtocol1{
    func callLoginAPI()
    {
        debugPrint("Inisde--MyManager1 and ready to call an Login API")
    }
}

struct MyManager2: MyProtocol2{
    func callPaymentAPI()
    {
        debugPrint("Inisde--MyManager2 and ready to call Payment API")
    }
}

Я хочу использовать фабричный шаблон для создания экземпляра Manager, передав протокол и вернув конкретный объект структуры, соответствующий этому протоколу

Пример: ManagerFactory.create(MyProtocol1) --> should give me instance of MyManager1 and doing ManagerFactory.create(MyProtocol2) --> should give me instance of MyManager2

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

protocol IManagerFactory{
    func getMyManager1() -> MyProtocol1
    func getMyManager2() -> MyProtocol2
}

struct ManagerFactory: IManagerFactory
{
    func getMyManager1() -> MyProtocol1 {
        return MyManager1()
    }

    func getMyManager2() -> MyProtocol2 {
        return MyManager2()
    }
}

Но мне любопытно, что яЯ пытаюсь сделать в примере достижимо, я использую Swift 4.2.

Я видел другие примеры, но все они имеют один и тот же протокол, который они соответствуют, как прямоугольник, квадрат и круг соответствуют одной и той же форме протокола.

В моем случае у меня есть два отдельных протокола, которые делают совершенно разные вещи, поэтому возможно ли то, что я пытаюсь сделать в этом примере?ИЛИ способ, которым я закончил, - единственный способ сделать это.

Пожалуйста, предложите, какой подход наилучший.

Ответы [ 2 ]

0 голосов
/ 03 февраля 2019

Во-первых, я очень подозрительно отношусь к «менеджеру», который является значением (структурой), а не экземпляром (классом).Вы действительно хотите использовать здесь структуры и протоколы?Структуры не имеют идентичности;две структуры с одинаковыми свойствами должны быть полностью взаимозаменяемыми друг с другом, и подобные вещи обычно не называют "manager".

То, что вы описываете, безусловно, доступно для записи.Это просто бесполезно.Вот как вы пишете:

struct ManagerFactory {
    static func create(_ type: MyProtocol1.Protocol) -> MyProtocol1 {
        return MyManager1()
    }

    static func create(_ type: MyProtocol2.Protocol) -> MyProtocol2 {
        return MyManager2()
    }
}

let mgr1 = ManagerFactory.create(MyProtocol1.self)
let mgr2 = ManagerFactory.create(MyProtocol2.self)

Но это всего лишь сложный способ использовать перегрузку методов для замены имен.

То, что вам нужно, это единственный метод, но что бы еготип возврата будет?Даже в C # я не думаю, что это доступно для записи без добавления отвратительных ударов.(Это точка, которую вы и paulw11 обсуждаете в комментариях.) Это не ограничение Swift;это фундаментальная характеристика типов.Даже в JavaScript вам нужно знать, что вы ожидаете получить, иначе вы не будете знать, какие методы вы можете вызвать для него (просто вы отслеживаете это ожидание в своей голове и документации, а не в компиляторе и коде)..

Похоже, вы создали здесь множество протоколов, и я держу пари, что они в основном имеют ровно одну реализацию.Это плохо, Свифт.Не создавайте протоколы, пока у вас нет особой потребности в них.Не создавайте аттракционы для развлечения.Они сожгут вас очень быстро.

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

struct API {
    let login: () -> Void
    let payment: () -> Void
}

let myAPI = API(login: myLoginFunction, payment: myPaymentFunction)

Это позволит вам создавать различные API, если они вам нужны.Но опять же, только если вам нужна эта гибкость.Если нет, просто используйте классы для экземпляров и структуры для значений и избегайте протоколов, пока в вашей программе не будет хотя бы 2, а лучше 3 реализации.

0 голосов
/ 03 февраля 2019

Предложите быстрый вариант:

protocol Manager {
    // a generic protocol for all managers
}

protocol BadManager: Manager {
    // properties and behaviour of BadManager
    mutating func noBonus()
}

protocol GoodManager: Manager {
    // properties and behaviour of GoodManager
    mutating func bigBonus()
}

protocol ManagerFactory {
    associatedtype Manager
    mutating func createManager() -> Manager
}

struct gm: GoodManager {
    mutating func bigBonus() {
        print("tons of cookies & coffee")
    }
}

struct bm: BadManager {
    mutating func noBonus() {
        print("all fired")
    }
}

enum ManagerCreator<Manager>: ManagerFactory {
    func createManager() -> Manager {
        switch self {
        case .goodManager:
            return gm() as! Manager
        case .badManager:
            return bm() as! Manager
        }
    }
    case goodManager
    case badManager
}
...