【问题标题】:swift: How to use protocols in place of abstract class?swift:如何使用协议代替抽象类?
【发布时间】:2016-11-15 07:20:00
【问题描述】:

我想知道如何使用协议来代替抽象类。下面是用抽象类编写的场景,我想在 swift 中使用协议来实现:

public abstract class ModelA
{
  protected int productQuantity;
  protected String productUrl;
}

class ModelB extends ModelA
{
  // I want to access ModelA members here
}

我想在 swift 中使用协议实现上述功能。 任何帮助将不胜感激。

【问题讨论】:

  • protocol ModelA { var productQuantity :Int{get set} var productUrl:String {get set} } class ModelB:ModelA{ var productQuantity :Int = 10 var productUrl:String = "Some URl" }

标签: java swift protocols abstract-class


【解决方案1】:

协议的实现应该是:

protocol ModelA {
    // props
    var productQuantity: Int { get set }
    var productUrl:String { get set }
}

“我想在这里访问 ModelA 成员”,实际上你必须在 ModelB 中实现 ModelA 属性。否则,你会得到一个编译错误:

模型B:

class ModelB: ModelA {
    // default values
    var productQuantity: Int = 0
    var productUrl: String = ""

    // you can remove the default values after implementing 'init':
    init(productQuantity: Int, productUrl: String) {
        self.productQuantity = productQuantity
        self.productUrl = productUrl
    }
}

有关协议的更多信息,请查看Apple Documentation

【讨论】:

    【解决方案2】:

    这是一个简单的例子,更多细节你可以看看Apple Docs

    protocol Shape {
        var width: Double { get set}
        var height: Double { get set}
        func area() -> Double
        func perimeter() -> Double
    }
    
    class Rectangle:Shape
    {
        var width: Double
        var height: Double
    
        init()
        {
            width = 0.0
            height = 0.0
        }
        convenience init(width:Double, height:Double)
        {
            self.init()
            self.width = width
            self.height = height
        }
        func area() -> Double {
            return width * height
        }
    
        func perimeter() -> Double {
            return 2 * (width + height)
        }
    }
    

    |

        var rect = Rectangle(width: 5.0, height: 5.0)
        print(rect.area())
        print(rect.perimeter())
    
        rect = Rectangle()
        print(rect.area())
        print(rect.perimeter())
    
        rect.width = 10
        rect.height = 10
        print(rect.area())
        print(rect.perimeter())
    

    【讨论】:

    • 从我读到的协议作为 swift 中的接口工作。但这迫使我在派生类中实现所有属性或函数。如果我想要一个派生类中的一些属性和另一个派生类中的一些属性?我可以使用抽象类来实现。
    • 在 Swift 中,您不能在协议中拥有可选的属性或方法,但是您可以通过使其 objc 符合 @objc 来声明(更多信息请访问 - devforums.apple.com/message/994834#994834)。如果你想使用类 1 中的一些属性和类 2 中的一些属性,这仅仅意味着这些属性不应该在协议中声明,或者只是分配一些默认值而不使用它们。
    • 以你的例子为例,如果我在 Shape 协议中有另一个名为 radius 的变量和一个实现 shape 来计算面积和周长的类 Circle,而 Circle 类只需要半径,既不宽度也不高度。我应该如何实施?因为不推荐使用可选属性,所以我不能使用它。
    • 您也可以使用计算属性(developer.apple.com/library/content/documentation/Swift/…)。在圆的情况下,您的 radius=width=height 是计算属性,因此您无需声明另一个属性,而是可以将属性存储为半径。
    【解决方案3】:

    你可以这样写:

    @objc protocol modelA
    {
      @objc optional productQuantity:Int { get set }
      @objc optional productUrl:String { get set }
    }
    

    然后在一个类中使用它

    class ModelB: ModelA {
      // you can implement OR NOT the attributes here
    }
    

    来自苹果文档:

    https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html

    您可以定义协议的可选要求,这些要求 不必由符合协议的类型实现。 可选要求以可选修饰符作为前缀,作为 协议的定义。可选要求是可用的,以便 您可以编写与 Objective-C 互操作的代码。这俩 协议和可选要求必须用@objc 标记 属性。请注意,@objc 协议只能由类采用 从 Objective-C 类或其他 @objc 类继承。他们 不能被结构或枚举采用。

    但老实说,如果您想真正保持代码清晰,这并不是最好的方法。抽象类没有明确定义谁将实现函数。我不知道您最终要实现什么目标,但也许扩展可以帮助您向某些类添加功能,而无需事先在协议中定义它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-08
      • 1970-01-01
      • 2016-04-18
      • 1970-01-01
      • 2021-12-20
      • 1970-01-01
      • 2017-10-12
      • 1970-01-01
      相关资源
      最近更新 更多