Я пытаюсь выполнить протокольное программирование в Swift 3 с использованием дженериков. Это еще не полностью поддерживается? Я собираюсь показать вам, что мне понравится делать ниже, но не будет компилироваться. Я что-то упустил? Моя цель - использовать протокол-ориентированное программирование для выполнения инъекции зависимостей с целью легко издеваться над этими структурами в моих модульных тестах.Можно ли передавать общие протоколы в конструктор для правильной инъекции зависимостей в Swift 3?
protocol ZombieServiceProtocol {
func fetchZombies()
var zombieRepository: RepositoryProtocol<Zombie> { get set }
}
struct ZombieService: ZombieServiceProtocol {
var zombieRepository: RepositoryProtocol<Zombie>
init(zombieRepository: RepositoryProtocol<Zombie>) {
self.zombieRepository = zombieRepository
}
func fetchZombies() {
self.zombieRepository.deleteAll()
self.createFakeZombies()
}
private func createFakeZombies() {
for index in 1...100 {
let zombie = Zombie(id: index, name: "Zombie \(index)")
self.zombieRepository.insert(zombie)
}
}
}
Класс зомби выглядит следующим образом:
public struct Zombie: Persistable {
var id: Int
let name: String?
init(id: Int, name: String?) {
self.id = id
self.name =name
}
}
Его Persistable протокол выглядит следующим образом:
protocol Persistable {
var id: Int { get set }
}
И мой Repository код выглядит примерно так:
protocol RepositoryProtocol: class {
associatedtype Object: Persistable
//...
func insert(_ object: Object) -> Void
func deleteAll(_ predicate: (Object) throws -> Bool) -> Void
}
class Repository<Object: Persistable>: RepositoryProtocol {
var items = Array<Object>()
//...
func insert(_ object: Object) {
self.items.append(object)
}
func deleteAll() {
self.items.removeAll()
}
}
Я получаю followi нг ошибка в моей ZombieServiceProtocol:
- Не может специализироваться необщего типа «RepositoryProtocol»
Я получаю следующее сообщение об ошибке в моем ZombieService:
- Не может специализироваться без универсального типа «RepositoryProtocol '
- Member' insert 'не может использоваться для значения типа протокола ' RepositoryProtocol '; вместо этого используйте общее ограничение
И, чтобы точно указать, что я пытаюсь выполнить, вот как выглядит простой тест, в котором я создаю репозиторий Mock и пытаюсь использовать его вместо реального в мой ZombieService:
@testable import ZombieInjection
class ZombieServiceTests: XCTestCase {
private var zombieRepository: RepositoryProtocol<Zombie>!
private var zombieService: ZombieServiceProtocol
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
self.zombieRepository = RepositoryMock<Zombie>()
self.zombieService = ZombieService(zombieRepository: self.zombieRepository)
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// Arrange
// Act
self.zombieService.fetchZombies()
// Assert
XCTAssert(self.zombieRepository.count() > 0)
}
}
Этот код также не компилируется в настоящее время с теми же ошибками, что и выше.
Я смотрел на связанные типы и теги типаAlias, а также на Generics Manifesto. Рассматривая Манифест, я считаю, что это относится к разделу «Общие протоколы», который в настоящее время отмечен как «Невероятно» (который меня избивает). Если я не смогу выполнить что-то вроде того, что я пытаюсь сделать выше, что будет лучшим решением?
Глядя, как звучит no? Попытка и рефакторинг, чтобы увидеть, что еще я могу сделать ... – PkL728