Untuk alasan apa Anda menggunakan ekstensi kelas terpisah untuk setiap delegasi di Swift?

13

Saya sedang mengerjakan tutorial Ray Wenderlich dan memperhatikan bahwa penulis menggunakan ekstensi kelas untuk menahan panggilan balik delegasi daripada meminta mereka ditangani di dalam kelas itu sendiri yaitu:

delegasikan panggilan balik di dalam ekstensi kelas:

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

sebagai lawan memilikinya terkandung di dalam kelas:

delegasikan panggilan balik di dalam kelas:

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

Saya menemukan ini aneh dan menarik pada saat bersamaan. Dia memiliki file yang didedikasikan hanya untuk ekstensi pada kelas LogsViewController bernama "LogsViewControllerExtension.swift" dan memiliki ekstensi yang berbeda untuk setiap protokol delegasi: UITableViewDataSource, UISplitViewDelegate, dll yaitu:

beberapa ekstensi kelas masing-masing dengan panggilan balik delegasi di dalam file sendiri:

extension LogsViewController: UISplitViewControllerDelegate {
    ... callbacks
}

extension LogsViewController : UIPopoverPresentationControllerDelegate {
    ... callbacks
}

Mengapa?

Apa manfaatnya melakukan ini? Saya bisa melihat di mana itu mungkin sedikit lebih mudah dibaca untuk memisahkan ini tetapi pada saat yang sama itu adalah tingkat tipuan. Apakah ada prinsip-prinsip OO yang mendukung atau menentang melakukan ini?

morbidhawk
sumber
1
Anda dapat menulis banyak struktur seperti ini yang secara fundamental didukung oleh prinsip-prinsip OO tetapi masih bersalah karena rekayasa berlebihan.
Robert Harvey
1
@RobertHarvey benar, tetapi apakah Anda menyiratkan bahwa contoh kode yang saya tunjukkan di sini adalah bentuk rekayasa ulang? Delegasi adalah pola umum dalam pengembangan iOS. Juga, apakah Anda menggunakan ekstensi kelas atau tidak tidak mengubah kode di dalamnya, jadi itu akan lebih seperti restrukturisasi kode daripada re (/ over) -engineering
morbidhawk
1
Saya melihat pola melempar banyak ekstensi ke file yang sama, dan saya tidak tahu dari mana ini berasal. Tampaknya beberapa orang sudah menyalahgunakannya dan hanya secara sewenang-wenang melemparkan setiap bit kode ke ekstensi dalam file yang sama. Saya yakin ada alasan bagus untuk melakukan ini pada kesempatan tertentu, tetapi saya mendapat kesan beberapa programmer hanya melakukannya tanpa mengerti mengapa. Saya terus mencari keuntungan dari ini menggunakan MARK: - dan akan senang menemukan beberapa sumber pasti tentang mengapa ekstensi harus digunakan dengan cara ini.
David Lari

Jawaban:

15

Saya tidak tahu mengapa Anda mengatakan itu menambah tingkat tipuan. Mungkin Anda memaksudkan sesuatu yang berbeda dengan itu daripada makna tradisional, karena tidak ada tipuan ekstra yang dibuat dengan melakukan ini. Tetapi mengapa melakukannya?

Saya melakukannya karena lebih modular. Semua kode yang diperlukan oleh antarmuka dikelompokkan dalam satu tempat (kecuali properti aktual). Jika saya kemudian memilih untuk membuat kelas terpisah untuk mengimplementasikan protokol itu (dan dengan demikian memperkenalkan tingkat tipuan yang sebenarnya,) semua yang saya butuhkan lakukan adalah mengubah ekstensi menjadi kelas itu sendiri (melewati properti yang dibutuhkan melalui fungsi init,) dan membuat properti pada ViewController untuk membuat instance objek menjadi.

Saya juga memasukkan fungsi pribadi yang hanya digunakan oleh fungsi protokol itu ke dalam ekstensi. Sejauh ini saya belum membuat file yang benar-benar terpisah untuk ekstensi, tetapi hal itu membuatnya jelas bahwa fungsi-fungsi pribadi hanya untuk protokol itu.

Dan bagaimanapun juga, orang sering mengeluh tentang pengontrol tampilan gemuk dan memutus pengontrol tampilan dengan cara ini membantu membuatnya lebih teratur, bahkan jika itu tidak benar-benar membuat pengontrol tampilan lebih tipis.

Daniel T.
sumber
Saya melihat apa yang Anda maksud dengan modularitas. Setelah saya mengerti apa yang sedang terjadi, itu terlihat seperti cara yang bersih untuk memisahkan masalah. Tingkat tipuan yang saya pikir adalah untuk satu set mata baru (dan saya bias datang dari cara Obj-c). Saya merasakan tingkat tipuan yang sama ketika subclassing di mana kode direferensikan yang didefinisikan di tempat lain di kelas dasar dan yang sedikit lebih sulit untuk menemukannya. Saya setuju bahwa secara organisasi itu menambah manfaat (dengan sedikit biaya tidak langsung)
morbidhawk
Saya kira ini telah dilakukan sebelumnya dengan kategori kelas di Obj-C. Saya tidak pernah terlalu menyukai itu, tetapi saya pikir mereka membutuhkan file terpisah. Karena sekarang di Swift Anda dapat menyimpan ekstensi dalam file yang sama itulah yang mungkin akan saya lakukan jika saya memutuskan untuk memecahnya seperti itu
morbidhawk
2

Seperti yang Daniel katakan mengenai tipuan, tidak ada levelnya.
Saya menyetujuinya dan saya ingin menambahkan fitur Protokol Perpanjangan yang sangat kuat yang saya ketahui baru-baru ini.

Katakanlah Anda memiliki protokol didCopyTextmisalnya. Anda akan menerapkannya sebagai:

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

Dalam Swift, properti dan metode tidak diimplementasikan dalam deklarasi Protokol, Anda ingin menulis implementasi di setiap kelas sesuai dengan didCopyText, dengan jumlah kelas tambahan sesuai dengan protokol ini dengan implementasi yang sama, itu akan berakhir dengan hanya berantakan kode berulang. Di situlah Perpanjangan Protokol berguna.

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

Dengan penerapan properti & metode protokol. Sekarang, setiap kelas yang sesuai dengan protokol ini, akan menggunakan implementasi yang sama.

MEnnabah
sumber
terima kasih sudah berbagi ini. Pada saat saya mengajukan pertanyaan ini, saya tidak menyadari tentang beberapa kelemahan dari warisan OO, dan apa yang Anda uraikan di sini adalah cara yang bagus untuk mendapatkan fungsi yang sama digunakan kembali oleh semua kelas pelaksana yang sesuai dengan antarmuka itu daripada dipaksa untuk mewarisi segalanya dari suatu objek. Dan jika Anda mengikuti prinsip Segregasi Antarmuka Anda dapat memecah protokol yang diperlukan untuk memastikan kelas implementasi tidak pernah memiliki properti / metode dari antarmuka yang tidak mereka butuhkan.
morbidhawk
1

Katakanlah kelas Anda mendukung tiga protokol, dan karena itu Anda harus menambahkan tiga set fungsi. Satu-satunya tujuan fungsi-fungsi ini adalah untuk mendukung protokol, sehingga Anda memerlukan beberapa dokumentasi.

Namun, jika Anda menambahkan ekstensi untuk setiap protokol, dan di setiap ekstensi Anda menerapkan persis fungsi yang diperlukan untuk satu protokol itu, yang membuat kode Anda jauh lebih mudah dibaca.

Saya kemungkinan besar tidak akan memasukkannya ke file terpisah kecuali ekstensi ini benar-benar besar.

gnasher729
sumber