Swift关联类型的协议

3

我该如何纠正错误?!

域模块,包含所有抽象内容。

//MARK: - Domain
protocol TypeB {
    associatedtype P
    func makeP() -> P
    init()
}

protocol TypeA {
    associatedtype P
    associatedtype B: TypeB
    
    func makeP() -> P
    init(objB: B)
}

protocol FirstTargetFabricType {
    func makeB<B: TypeB>() -> B where B.P == Int
}

protocol SecondTargetFabricType {
    func makeA<B, A: TypeA>(objcB: B) -> A where A.B == B, A.P == B.P, B.P == Int
}

例如用于网络工作的第一个模块。
//MARK: - First Target
class ClassB: TypeB {
    required init() { }
    func makeP() -> Double { return 10 }
}


// error: Cannot convert return expression of type 'ClassB' to return type 'B'
class FirstTargetFabric: FirstTargetFabricType {
    func makeB<B: TypeB>() -> B where B.P == Int {
        return ClassB()
    }
}

例如处理存储的第二个模块

//MARK: - SecondTarget
    class ClassA<B: TypeB>: TypeA {
        let objB: B
        
        required init(objB: B) {
            self.objB = objB
        }
        
        func makeP() -> B.P { return objB.makeP() }
    }
    
    class SecondTargetFabric: SecondTargetFabricType {
        func makeA<B, A: TypeA>(objcB: B) -> A where B == A.B, B.P == A.P, B.P == Int {
            return A(objB: objcB)
        }
    }

应用程序目标
//MARK: - app
let firstFabric: FirstTargetFabricType = FirstTargetFabric()
let secondFabric: SecondTargetFabricType = SecondTargetFabric()

/// error: Generic parameter 'A' could not be inferred
let res = secondFabric.makeA(objcB: firstFabric.makeB())

我正在尝试制作一个用于分页的服务加载器。我只想在类初始化器中传入一个将要前往网络的实体。

3个回答

1
这个方法会有多好?
 //MARK: - Domain
open class TypeB<T: Decodable> {
    open func makeP() -> T {
        fatalError("Required function have not been implemented")
    }
}

open class TypeA<T: Decodable> {
    open func makeP() -> T {
        fatalError("Required function have not been implemented")
    }
}

public protocol FirstTargetFabricType {
    func makeInt() -> TypeB<Int>
    func makeDouble() -> TypeB<Double>
}

public protocol SecondTargetFabricType {
    func makeInt(objInt: TypeB<Int>) -> TypeA<Int>
    func makeDouble(objDouble: TypeB<Double>) -> TypeA<Double>
}



//MARK: - First Target
internal class ClassB: TypeB<Int> {
    override func makeP() -> Int { return 10 }
}

internal class ClassBB: TypeB<Double> {
    override func makeP() -> Double { return 20 }
}

public class FirstTargetFabric: FirstTargetFabricType {
    public func makeInt() -> TypeB<Int> { ClassB() }
    public func makeDouble() -> TypeB<Double> { ClassBB() }
}



//MARK: - SecondTarget
internal class ClassA: TypeA<Int> {
    let objB: TypeB<Int>

    init(objB: TypeB<Int>) {
        self.objB = objB
    }
    
    override func makeP() -> Int {
        objB.makeP()
    }
}

internal class ClassAA: TypeA<Double> {
    let objB: TypeB<Double>

    init(objB: TypeB<Double>) {
        self.objB = objB
    }
    
    override func makeP() -> Double {
        objB.makeP()
    }
}

public class SecondTargetFabric: SecondTargetFabricType {
    public func makeInt(objInt: TypeB<Int>) -> TypeA<Int> { ClassA(objB: objInt) }
    public func makeDouble(objDouble: TypeB<Double>) -> TypeA<Double> { ClassAA(objB: objDouble) }
}


//MARK: - app
let first = FirstTargetFabric()
let second = SecondTargetFabric()

let objInt = first.makeInt()
let objDouble = first.makeDouble()


print(second.makeInt(objInt: objInt).makeP())
print(second.makeDouble(objDouble: objDouble).makeP())

0

这是使用协议的正确方法,但如果您继续使用关联协议,可能会变得非常复杂。

在makeAa方法中,您试图将TypeA作为类型A返回,而并非所有TypeA都是A,因此您必须返回A。

protocol TypeA {
    associatedtype P
    associatedtype B: TypeB
    
    func makeP() -> P
    init(objB: B)
}

protocol TypeB {
    associatedtype P
    func makeP() -> P
}

class ClassB: TypeB {
    func makeP() -> Int { return 10 }
}

class ClassA<B: TypeB>: TypeA {
    
    let objB: B
    
    required init(objB: B) {
        self.objB = objB
    }
    
    func makeP() -> B.P {
        return objB.makeP()
    }
}

//**Cannot convert return expression of type 'ClassA<B>' to return type 'A'**
func makeAa<B, A: TypeA>(objB: B) -> A where B.P == Int, A.P == B.P, A.B == B {
    return A(objB: objB)
}


//**Generic parameter 'A' could not be inferred**
let res: ClassA = makeAa(objB: ClassB())

也许您可以告诉我如何分担责任。这样,一个类负责一部分工作,第二个类负责第二部分工作?希望您明白我的意思:)我需要一个抽象,因为实现在不同的目标中。 - user10224777
1
你在代码中使用的方法很好,协议和依赖注入使关系松散。要将两个不同的对象/服务组合起来,有许多已知的模式(请参见四人帮设计模式)。但是你在这里使用的方法被广泛使用。 - Vitalii Shvetsov
你好,请再看一下,我稍微扩充了一下问题!理解协议确实很难,但并不是说我无法编译通过! - user10224777
@voragomod 创建了另一个答案。 - Vitalii Shvetsov

0

关于更新: 再次强调,你必须返回类型B,而不是所有的ClassB都是B()

// error: Cannot convert return expression of type 'ClassB' to return type 'B'
class FirstTargetFabric: FirstTargetFabricType {
    func makeB<B: TypeB>() -> B where B.P == Int {
        return B()
    }
}

在这里,您需要指定要创建的通用类B(ClassB)

/// error: Generic parameter 'A' could not be inferred
let b: ClassB = firstFabric.makeB()
let res: ClassA = secondFabric.makeA(objcB: b)

而ClassB应该返回与ClassA相同的(Int)以将它们合并

//MARK: - First Target
class ClassB: TypeB {
    required init() { }
    func makeP() -> Int { return 10 }
}

我已经到这一步了,但我不明白是否可以将ClassB和ClassA隐藏在目标内,并通过工厂传递它们? - user10224777
是的,您可以在工厂方法中删除泛型。最终代码如下:func buildA() -> A { return ClassA() }。在这种情况下,您不需要泛型,因为您希望它成为一个模糊类型,以便您可以注入它。 - Vitalii Shvetsov
请问您能否评估一下最后的方法?! - user10224777
1
谢谢,我只是远程工作,没有团队领导。 - user10224777

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接