Swift:具有私有成员的抽象基 class/protocol
Swift: Abstract base class/protocol with private members
我根据 this answer 使用协议扩展在 Swift 中创建了一个类似于 class 的抽象结构。这是一个简化的例子:
protocol AbstractBase {
var _constant: Int { get }
func _operation(_ val: Int) -> Int
}
public class ConcreteSub: AbstractBase {
let _constant: Int = 42
func _operation(_ val: Int) -> Int {
return val + 2
}
}
extension AbstractBase {
func mainOperation(_ val: Int) -> Int {
return _operation(val + _constant)
}
}
所以基本上,ConcreteSub
提供了 AbstractBase
所需的实现细节,即 _constant
和 _operation
。
我想对客户隐藏这些细节,只公开 mainOperation
。但是,Swift 不允许我在协议上将成员设为私有文件——如果我执行以下操作
protocol AbstractBase {
fileprivate var _constant: Int { get }
// etc
我得到 "error: 'fileprivate' modifier cannot be used in protocols"。
我也不能在 subclass 上应用修饰符 -- 当我尝试时
public class ConcreteSub: AbstractBase {
fileprivate let _constant: Int = 42
// etc
我得到 "error: property '_constant' must be declared internal because it matches a requirement in internal protocol 'AbstractBase'"。
最后,当我将整个协议文件设为私有时,我没有遇到任何编译错误,但我一直 运行 进入链接错误,我猜这是因为协议是私有的,但是 subclass 是 public.
还有其他我想念的方法吗?
当我需要一个隐藏了一些 properties/functions 的抽象基础时,我使用 class 和一些额外的 fatalErrors
和 asserts
来在有人尝试使用 Base 时崩溃实施。
public class AbstractBase {
init() {
assert(type(of: self) != AbstractBase.self, "Abstract class")
}
fileprivate var _constant: Int {
fatalError("Abstract class")
}
fileprivate func _operation(_ val: Int) -> Int {
fatalError("Abstract class")
}
func mainOperation(_ val: Int) -> Int {
return _operation(val + _constant)
}
}
public class ConcreteSub: AbstractBase {
fileprivate override var _constant: Int {
return 42
}
fileprivate override func _operation(_ val: Int) -> Int {
return val + 2
}
}
实际上我只是 运行 关注这个问题。从 Swift 5.1 开始,您可以改为这样做:
protocol MyProtocol {
var someVisibleVar: String { get }
func someVisibleFunc()
}
fileprivate extension MyProtocol {
var someFilePrivateVar: String {
"whatever"
}
func someFilePrivateFunc() {
print("someFilePrivateFunc() was called with \(someVisibleVar)")
}
}
class SomeClass: MyProtocol {
var someVisibleVar: String { "whatever" }
func someVisibleFunc() {
if someFilePrivateVar == someVisibleVar {
someFilePrivateFunc()
}
}
}
class SomeOtherClass: MyProtocol {
var someVisibleVar: String { "something else" }
func someVisibleFunc() {
if someFilePrivateVar == someVisibleVar {
someFilePrivateFunc()
}
}
}
我根据 this answer 使用协议扩展在 Swift 中创建了一个类似于 class 的抽象结构。这是一个简化的例子:
protocol AbstractBase {
var _constant: Int { get }
func _operation(_ val: Int) -> Int
}
public class ConcreteSub: AbstractBase {
let _constant: Int = 42
func _operation(_ val: Int) -> Int {
return val + 2
}
}
extension AbstractBase {
func mainOperation(_ val: Int) -> Int {
return _operation(val + _constant)
}
}
所以基本上,ConcreteSub
提供了 AbstractBase
所需的实现细节,即 _constant
和 _operation
。
我想对客户隐藏这些细节,只公开 mainOperation
。但是,Swift 不允许我在协议上将成员设为私有文件——如果我执行以下操作
protocol AbstractBase {
fileprivate var _constant: Int { get }
// etc
我得到 "error: 'fileprivate' modifier cannot be used in protocols"。
我也不能在 subclass 上应用修饰符 -- 当我尝试时
public class ConcreteSub: AbstractBase {
fileprivate let _constant: Int = 42
// etc
我得到 "error: property '_constant' must be declared internal because it matches a requirement in internal protocol 'AbstractBase'"。
最后,当我将整个协议文件设为私有时,我没有遇到任何编译错误,但我一直 运行 进入链接错误,我猜这是因为协议是私有的,但是 subclass 是 public.
还有其他我想念的方法吗?
当我需要一个隐藏了一些 properties/functions 的抽象基础时,我使用 class 和一些额外的 fatalErrors
和 asserts
来在有人尝试使用 Base 时崩溃实施。
public class AbstractBase {
init() {
assert(type(of: self) != AbstractBase.self, "Abstract class")
}
fileprivate var _constant: Int {
fatalError("Abstract class")
}
fileprivate func _operation(_ val: Int) -> Int {
fatalError("Abstract class")
}
func mainOperation(_ val: Int) -> Int {
return _operation(val + _constant)
}
}
public class ConcreteSub: AbstractBase {
fileprivate override var _constant: Int {
return 42
}
fileprivate override func _operation(_ val: Int) -> Int {
return val + 2
}
}
实际上我只是 运行 关注这个问题。从 Swift 5.1 开始,您可以改为这样做:
protocol MyProtocol {
var someVisibleVar: String { get }
func someVisibleFunc()
}
fileprivate extension MyProtocol {
var someFilePrivateVar: String {
"whatever"
}
func someFilePrivateFunc() {
print("someFilePrivateFunc() was called with \(someVisibleVar)")
}
}
class SomeClass: MyProtocol {
var someVisibleVar: String { "whatever" }
func someVisibleFunc() {
if someFilePrivateVar == someVisibleVar {
someFilePrivateFunc()
}
}
}
class SomeOtherClass: MyProtocol {
var someVisibleVar: String { "something else" }
func someVisibleFunc() {
if someFilePrivateVar == someVisibleVar {
someFilePrivateFunc()
}
}
}