web-dev-qa-db-ja.com

Swiftの各デリゲートに個別のクラス拡張を使用する理由は何ですか?

私はRay Wenderlichのチュートリアルを進めていたところ、作成者がクラス拡張を使用して、デリゲートコールバックをクラス自体で処理するのではなく保持することに気付きました。

クラス拡張内のコールバックのデリゲート:

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

クラス内に含めるのではなく、

クラス内のコールバックのデリゲート:

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

同時に、これは奇妙で興味深いものでした。彼は "LogsViewControllerExtension.Swift"という名前のLogsViewControllerクラスの拡張専用のファイルを持ち、各デリゲートプロトコルごとに異なる拡張を持っています:UITableViewDataSource、UISplitViewDelegateなど。

それぞれのファイル内のデリゲートコールバックを含む複数のクラス拡張:

extension LogsViewController: UISplitViewControllerDelegate {
    ... callbacks
}

extension LogsViewController : UIPopoverPresentationControllerDelegate {
    ... callbacks
}

どうして?

これを行うことにはどのような利点がありますか?これを分離する方が少し読みやすいかもしれませんが、同時に間接参照のレベルです。 OOこれを支持または反対する原則はありますか?

13
morbidhawk

なぜそれが間接性のレベルを追加すると言ったのか、私にはわかりません。これを行うことによって作成される余分な間接参照がないため、おそらく、従来の意味とは異なる何かを意味するかもしれません。しかし、なぜそれをするのですか?

それがよりモジュール化されているので、私はそれをします。インターフェイスに必要なすべてのコードが1か所にグループ化されます(実際のプロパティを除く)。後でそのプロトコルを実装するために別のクラスを作成することを選択した場合(したがって、実際のレベルの間接参照を導入した場合)、必要なすべてのことそれには、拡張機能を独自のクラスに変更し(必要なプロパティをinit関数を介して渡します)、ViewControllerにプロパティを作成して、オブジェクトをインスタンス化します。

また、そのプロトコルの関数でのみ使用されるプライベート関数を拡張機能に追加しました。拡張子用に完全に別のファイルを作成するまでは行っていませんが、そうすることで、これらのプライベート関数はそのプロトコル専用であることが明らかになります。

とにかく、人々はしばしばビューコントローラーの太さに不満を抱き、ビューコントローラーをこのように分割することで、実際にビューコントローラーを薄くしなくても、より適切に整理することができます。

15
Daniel T.

間接に関してダニエルが言ったように、それのレベルはありません。
私は彼に同意し、最近知ったプロトコル拡張の強力な機能を追加したいと思います。

たとえば、プロトコルdidCopyTextがあるとします。次のように実装します。

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

Swiftでは、プロパティとメソッドはプロトコル宣言に実装されていません。すべてのクラスに実装を記述してdidCopyTextに準拠し、同じ実装でこのプロトコルに準拠するクラスの数を増やします。単に厄介な繰り返しコードで終わる。ここで、プロトコル拡張が役立ちます。

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

プロトコルのプロパティとメソッドの実装。これで、すべてのクラスがこのプロトコルに準拠し、同じ実装を使用します。

2
MEnnabah

クラスが3つのプロトコルをサポートしているため、3つの関数セットを追加する必要があるとします。これらの関数の唯一の目的はプロトコルをサポートすることであるため、いくつかのドキュメントが必要です。

ただし、各プロトコルに拡張機能を追加し、各拡張機能にその1つのプロトコルに必要な機能を正確に実装すると、コードがより読みやすくなります。

これらの拡張子が本当に大きい場合を除き、私はおそらくそれらを別々のファイルに入れません。

1
gnasher729