Те же объекты протокола, но не те же функции - PullRequest
0 голосов
/ 22 мая 2019

Я пытаюсь построить шаблон API.

У меня есть несколько разных API, которые имеют одни и те же функции для некоторых, а у некоторых есть дополнительные функции, которые другие API не имеют и не должны иметь к ним доступ.

Проблема с протоколом заключается в том, что все они имеют доступ. Как ограничить доступ, если функция не переопределена?

apiRequest:

class APIRequest {
    static func loginCli(completion: (UserClinic) -> ()) {

    }

    static func loginFami(completion: (User) -> ()) {

    }

    static func loginDavid(completion: (UserDavid) -> ()) {

    }
}

Protol и API:

protocol API {
    func login<T>(completion: (T) -> ())
    func saveClient()
}

extension API {
    func saveClient() {
        saveClient()
    }
}

class FirstAPI: API {
    func login<T>(completion: (T) -> ()) {
        APIRequest.loginFami { (user) in

        }
    }
}

class SecondAPI: API {
    func login<T>(completion: (T) -> ()) {
        APIRequest.loginCli { (user) in

        }
    }
}

class ThreeAPI: API {
    func login<T>(completion: (T) -> ()) {
        APIRequest.loginDavid { (user) in

        }
    }

    func saveClient() {
        // Save client
    }
}

Посмотреть модель:

class LoginViewModel {
    var apiClient: API

    init() {
        // Below its good
        apiClient = ThreeAPI()
        apiClient.saveClient()

        // Below its not good
        apiClient = FirstAPI()
        apiClient.saveClient() // I want this is not accessible

        // Below its good
        apiClient = SecondAPI()
        apiClient.saveClient() // I want this is not accessible
    }
}

В моем случае мне нужен только третий API для доступа к функции saveClient()

Ответы [ 3 ]

0 голосов
/ 22 мая 2019

Если вам не нужен метод saveClient для FirstAPI и SecondAPI, вам нужно извлечь этот метод в отдельный протокол. Что-то вроде:

protocol APIThatCanLogin {
    func login<T>(completion: (T) -> ())
}

protocol APIThatCanSave {
    func saveClient()
}


class FirstAPI: APIThatCanLogin { }
class SecondAPI: APIThatCanLogin { }
class ThreeAPI: APIThatCanLogin, APIThatCanSave { }

Но, возможно, вам следует пересмотреть использование протоколов. По крайней мере, в этом примере это не дает никаких преимуществ.

0 голосов
/ 22 мая 2019

Там не будет решения, как описано.Тип API означает"имеет следующие методы и свойства."Вы не можете присвоить что-либо переменной типа API и затем сказать «но у нее нет некоторых методов».Это нарушает LSP , что является основой этих типов.Рассмотрим следующий код:

func save(api: API) {
    api.saveClient()
}

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

Если вы хотите, чтобы saveClient был неактивным (бездействующим), то это очень просто.Предоставьте пустую реализацию по умолчанию:

extension API {
    func saveClient() {}
}

Если вы хотите, чтобы некоторые API были сохраняемыми, а некоторые не были сохраняемыми, то это тоже просто:

protocol API {
    func login<T>(completion: (T) -> ())
}

protocol SavableAPI: API {
    func saveClient()
}

Но initметод, который вы написали, нельзя заставить работать.Это нарушает основную цель наличия типа.

0 голосов
/ 22 мая 2019

Попробуй это.

protocol API {
    func login<T>(completion: (T) -> ())
}

extension API where Self: ThreeAPI {
    func saveClient() {

    }
}

В приведенном выше коде protocol API extension доступно только для объекта типа ThreeAPI.

Я использовал ThreeAPI прямо здесь.Вы можете сделать common type для всех classes, которым требуется saveClient(), и использовать этот тип вместо ThreeAPI

Использование:

apiClient = ThreeAPI()
(apiClient as? ThreeAPI)?.saveClient()

apiClient = FirstAPI() //saveClient() not available

apiClient = SecondAPI() //saveClient() not available

Edit-1:

Создать CommonAPI родительский class для всех классов, которым требуется метод saveClient().

class CommonAPI {
    func saveClient() {
        print("CommonAPI saveClient()")
    }
}

Наследовать ThreeAPIи FourAPI из CommonAPI

class ThreeAPI: CommonAPI, API {
    func login<T>(completion: (T) -> ()) {

    }

    override func saveClient() {
        print("ThreeAPI saveClient()")
    }
}

class FourAPI: CommonAPI, API {
    func login<T>(completion: (T) -> ()) {

    }

    override func saveClient() {
        print("FourAPI saveClient()")
    }
}

Просто используйте switch statement для вызова saveClient() на всех объектах типа CommonAPI.

apiClient = FourAPI()
apiClient = ThreeAPI()
apiClient = FirstAPI()
apiClient = SecondAPI()

switch apiClient {
case is CommonAPI:
    (apiClient as? CommonAPI)?.saveClient()

default:
    break
}

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

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