tôi có mã sau thiết kế tổng thể của:sai chức năng chung chuyên ngành được gọi trong Swift 3 từ một cuộc gọi gián tiếp
protocol DispatchType {}
class DispatchType1: DispatchType {}
class DispatchType2: DispatchType {}
func doBar<D:DispatchType>(value:D) {
print("general function called")
}
func doBar(value:DispatchType1) {
print("DispatchType1 called")
}
func doBar(value:DispatchType2) {
print("DispatchType2 called")
}
nơi trong thực tế DispatchType
thực sự là một lưu trữ backend. Các chức năng doBar
là các phương pháp tối ưu hóa phụ thuộc vào loại lưu trữ chính xác. Tất cả mọi thứ hoạt động tốt nếu tôi làm:
let d1 = DispatchType1()
let d2 = DispatchType2()
doBar(value: d1) // "DispatchType1 called"
doBar(value: d2) // "DispatchType2 called"
Tuy nhiên, nếu tôi thực hiện một chức năng mà các cuộc gọi doBar
:
func test<D:DispatchType>(value:D) {
doBar(value: value)
}
và tôi cố gắng một mô hình gọi điện thoại tương tự, tôi nhận được:
test(value: d1) // "general function called"
test(value: d2) // "general function called"
Điều này có vẻ như một cái gì đó mà Swift sẽ có thể xử lý vì nó có thể xác định tại thời gian biên dịch các ràng buộc loại. Cũng như một bài kiểm tra nhanh, tôi cũng đã thử viết doBar
là:
func doBar<D:DispatchType>(value:D) where D:DispatchType1 {
print("DispatchType1 called")
}
func doBar<D:DispatchType>(value:D) where D:DispatchType2 {
print("DispatchType2 called")
}
nhưng nhận được kết quả tương tự.
Bất kỳ ý tưởng nào nếu đây là hành vi Swift đúng, và nếu có, cách tốt để giải quyết hành vi này là gì?
Chỉnh sửa 1: Ví dụ về lý do tôi cố tránh sử dụng giao thức. Giả sử tôi có mã (đơn giản hóa từ mã thực tế của tôi):
protocol Storage {
// ...
}
class Tensor<S:Storage> {
// ...
}
Đối với lớp Tensor
Tôi có một bộ cơ sở hoạt động có thể được thực hiện trên Tensor
s. Tuy nhiên, bản thân các hoạt động sẽ thay đổi hành vi của chúng dựa trên lưu trữ. Hiện nay tôi thực hiện điều này với:
func dot<S:Storage>(_ lhs:Tensor<S>, _ rhs:Tensor<S>) -> Tensor<S> { ... }
Trong khi tôi có thể đưa những trong Tensor
lớp và sử dụng phần mở rộng:
extension Tensor where S:CBlasStorage {
func dot(_ tensor:Tensor<S>) -> Tensor<S> {
// ...
}
}
này có một vài tác dụng phụ mà tôi không thích:
Tôi nghĩ rằng
dot(lhs, rhs)
thích hợp hơn làlhs.dot(rhs)
. Các chức năng tiện lợi có thể được viết để giải quyết vấn đề này, nhưng điều đó sẽ tạo ra một sự bùng nổ mã rất lớn.Điều này sẽ khiến lớp
Tensor
trở thành nguyên khối. Tôi thực sự thích có chứa số lượng mã tối thiểu cần thiết và mở rộng chức năng của nó bằng các chức năng phụ trợ.Liên quan đến (2), điều này có nghĩa là bất kỳ ai muốn thêm chức năng mới sẽ phải chạm vào lớp cơ sở mà tôi coi là thiết kế kém.
Chỉnh sửa 2: Một thay thế là những thứ làm việc dự kiến nếu bạn sử dụng hạn chế đối với tất cả mọi thứ:
func test<D:DispatchType>(value:D) where D:DispatchType1 {
doBar(value: value)
}
func test<D:DispatchType>(value:D) where D:DispatchType2 {
doBar(value: value)
}
sẽ làm cho đúng doBar
được gọi. Điều này cũng không phải là lý tưởng, vì nó sẽ gây ra rất nhiều mã bổ sung để được viết, nhưng ít nhất là cho phép tôi giữ thiết kế hiện tại của mình.
Chỉnh sửa 3: Tôi đã xem qua tài liệu cho biết việc sử dụng từ khóa static
với Generics. Điều này giúp ít nhất là với điểm (1):
class Tensor<S:Storage> {
// ...
static func cos(_ tensor:Tensor<S>) -> Tensor<S> {
// ...
}
}
cho phép bạn viết:
let result = Tensor.cos(value)
và nó hỗ trợ điều hành quá tải:
let result = value1 + value2
nó có tính cách rườm rà gia tăng của yêu cầu Tensor
. Điều này có thể làm tốt hơn một chút với:
typealias T<S:Storage> = Tensor<S>
Điều này xảy ra do cách thức Swift thực hiện phương thức gửi đi. Vui lòng xem https://www.raizlabs.com/dev/2016/12/swift-method-dispatch/ - đặc biệt là chương Reference Type Matters¨. – courteouselk
Liên quan: [Mở rộng Bộ sưu tập với thuộc tính/phương pháp đệ quy phụ thuộc vào loại phần tử] (http://stackoverflow.com/q/41640321/2976878) – Hamish
Hơi liên quan: [Cách gọi phương thức quá tải cụ thể hơn] (http://stackoverflow.com/questions/41531569/how-to-call-the-more-specific-method-of-overloading) – dfri