Vì lý do gì bạn sẽ sử dụng tiện ích mở rộng lớp riêng cho từng đại biểu trong Swift?


13

Tôi đã làm việc thông qua một hướng dẫn Ray Wenderlich và nhận thấy rằng tác giả sử dụng các phần mở rộng lớp để giữ các cuộc gọi lại đại biểu thay vì xử lý chúng trong chính lớp đó, ví dụ:

cuộc gọi lại đại biểu bên trong lớp mở rộng:

extension LogsViewController : UIPopoverPresentationControllerDelegate {
    func adaptivePresentationStyleForPresentationController(controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
        ...
    }
}

trái ngược với việc nó được chứa trong lớp:

cuộc gọi lại đại biểu trong lớp:

class LogsViewController : UITableViewController, UIPopoverPresentationControllerDelegate {
    func adaptivePresentationStyleForPresentationController(controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
        ...
    }
}

Tôi thấy điều này kỳ lạ và thú vị cùng một lúc. Anh ta có một tệp dành riêng cho các phần mở rộng trên lớp LogsViewControll có tên "LogsViewControllExtension.swift" và có một phần mở rộng khác nhau cho mỗi giao thức đại biểu: UITableViewDataSource, UISplitViewDelegate, v.v.

nhiều phần mở rộng lớp mỗi cuộc gọi lại ủy nhiệm trong tệp riêng của mình:

extension LogsViewController: UISplitViewControllerDelegate {
    ... callbacks
}

extension LogsViewController : UIPopoverPresentationControllerDelegate {
    ... callbacks
}

Tại sao?

Những lợi thế là gì để làm điều này? Tôi có thể thấy nơi nào có thể dễ đọc hơn một chút để phân tách điều này nhưng đồng thời nó là một mức độ không xác định. Có nguyên tắc OO nào hỗ trợ hoặc chống lại việc này không?


1
Bạn có thể viết rất nhiều cấu trúc như thế này, về cơ bản được hỗ trợ bởi các nguyên tắc OO nhưng vẫn phạm tội vì quá áp lực.
Robert Harvey

1
@RobertHarvey đúng, nhưng bạn có ngụ ý rằng mã ví dụ tôi đã trình bày ở đây là một hình thức áp đảo? Đoàn là một mô hình phổ biến trong phát triển iOS. Ngoài ra, cho dù bạn có sử dụng các tiện ích mở rộng lớp hay không không thay đổi mã bên trong nó, do đó, nó sẽ giống như tái cấu trúc mã hơn là tái cấu trúc (/ hơn)
morbidhawk

1
Tôi đang thấy mô hình ném một loạt các phần mở rộng vào cùng một tệp và tôi không biết điều này đến từ đâu. Có vẻ như một số người đã lạm dụng nó và chỉ tự ý ném từng chút mã vào một phần mở rộng trong cùng một tệp. Tôi chắc chắn có một lý do tốt để làm điều này trong dịp này, nhưng tôi có ấn tượng rằng một số lập trình viên chỉ đang làm điều đó mà không hiểu tại sao. Tôi tiếp tục tìm kiếm một lợi thế của việc này bằng cách sử dụng MARK: - và rất thích tìm một số nguồn chính xác về lý do tại sao các tiện ích mở rộng nên được sử dụng theo cách này.
David Lari

Câu trả lời:


15

Tôi không biết lý do tại sao bạn nói nó thêm một mức độ gián tiếp. Có thể bạn có ý nghĩa gì đó khác với ý nghĩa truyền thống, bởi vì không có sự gián tiếp thêm được tạo ra bằng cách làm điều này. Nhưng tại sao lại làm điều đó?

Tôi làm điều đó bởi vì nó là mô-đun nhiều hơn. Tất cả các mã được giao diện yêu cầu được nhóm lại ở một nơi duy nhất (ngoại trừ các thuộc tính thực tế.) Nếu sau này tôi chọn tạo một lớp riêng để thực hiện giao thức đó (và do đó giới thiệu một mức độ gián tiếp thực tế), tất cả những gì tôi cần làm là thay đổi phần mở rộng thành một lớp của chính nó (chuyển các thuộc tính cần thiết thông qua hàm init) và tạo một thuộc tính trên ViewContoder để khởi tạo đối tượng vào.

Tôi cũng đặt bất kỳ chức năng riêng tư nào chỉ được sử dụng bởi các chức năng của giao thức đó vào phần mở rộng. Tôi đã không đi xa để tạo một tệp hoàn toàn riêng biệt cho tiện ích mở rộng, nhưng làm như vậy cho thấy rõ rằng các chức năng riêng tư đó chỉ dành cho giao thức đó.

Và ở mọi mức độ, mọi người thường phàn nàn về bộ điều khiển xem chất béo và phá vỡ bộ điều khiển chế độ xem theo cách này giúp giữ cho nó được tổ chức tốt hơn, ngay cả khi nó không thực sự làm cho bộ điều khiển xem mỏng hơn.


Tôi thấy những gì bạn có ý nghĩa của mô-đun. Một khi tôi hiểu những gì đang xảy ra, nó trông giống như một cách rõ ràng để phân tách các mối quan tâm. Mức độ gián tiếp mà tôi nghĩ là dành cho một đôi mắt mới (và tôi thiên vị đến từ cách Obj-c). Tôi cảm thấy cùng một mức độ gián tiếp khi phân lớp trong đó mã đang được tham chiếu được xác định ở một nơi khác trong lớp cơ sở và khó tìm thấy nó hơn một chút. Tôi đồng ý rằng về mặt tổ chức, nó mang lại lợi ích (với một ít chi phí gián tiếp)
morbidhawk

Tôi đoán điều này đã được thực hiện trước đây với các thể loại lớp trong Obj-C. Tôi chưa bao giờ là một fan hâm mộ của những người đó nhưng tôi nghĩ họ yêu cầu một tập tin riêng. Kể từ bây giờ trong Swift, bạn có thể giữ phần mở rộng trong cùng một tệp đó là những gì tôi có thể làm nếu tôi quyết định chia nhỏ chúng như thế
morbidhawk

2

Như Daniel đã nói liên quan đến sự thiếu quyết đoán, không có mức độ nào của nó.
Tôi đồng ý với anh ấy và tôi muốn thêm tính năng mạnh mẽ của Tiện ích mở rộng giao thức mà tôi biết gần đây.

Nói rằng bạn có một giao thức didCopyTextchẳng hạn. Bạn sẽ thực hiện điều đó như:

protocol didCopyText {
  var charachtersCount: Int {get}
  func addToClipboardWith(text: String)
}

Trong Swift, các thuộc tính và phương thức không được triển khai trong khai báo Giao thức, bạn sẽ muốn viết việc triển khai trong mỗi lớp tuân theo didCopyText, với số lượng các lớp tăng dần theo giao thức này với cùng một triển khai, nó sẽ chỉ là một mớ hỗn độn mã lặp đi lặp lại. Đó là nơi Giao thức mở rộng có ích.

protocol didCopyText {
var charachtersCount: Int {
    get {
     // implementation
    }
}
func addToClipboardWith(text: String) {
      // implementation
 }
}

Với việc thực hiện các thuộc tính & phương thức của giao thức. Bây giờ, bất kỳ lớp nào phù hợp với giao thức này, sẽ sử dụng cùng một triển khai.


cảm ơn vì đã chia sẻ điều này Tại thời điểm tôi hỏi câu hỏi này, tôi đã không nhận ra một số nhược điểm của thừa kế OO và những gì bạn đang mô tả ở đây là một cách tuyệt vời để có được các chức năng tương tự được sử dụng bởi tất cả các lớp thực hiện theo giao diện đó thay vì bị ép buộc kế thừa mọi thứ từ một đối tượng. Và nếu bạn tuân theo nguyên tắc Phân chia Giao diện, bạn có thể tách các giao thức khi cần để đảm bảo các lớp triển khai không bao giờ có thuộc tính / phương thức từ giao diện mà chúng không cần.
morbidhawk

1

Giả sử lớp của bạn hỗ trợ ba giao thức và do đó bạn phải thêm ba bộ hàm. Mục đích duy nhất của các chức năng này là hỗ trợ một giao thức, vì vậy bạn cần một số tài liệu.

Tuy nhiên, nếu bạn thêm một tiện ích mở rộng cho mỗi giao thức và trong mỗi tiện ích mở rộng, bạn triển khai chính xác các chức năng cần thiết cho một giao thức đó, điều đó làm cho mã của bạn dễ đọc hơn rất nhiều.

Tôi rất có thể sẽ không đặt chúng vào các tệp riêng biệt trừ khi các tiện ích mở rộng này thực sự lớn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.