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


13

私はレイ・ウェンダリッヒのチュートリアルを進めていましたが、作者がクラス拡張機能を使用してデリゲートコールバックを保持していることに気付きました。

クラス拡張内のコールバックを委任する:

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
}

どうして?

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


1
基本的にオブジェクト指向の原則によってサポートされているが、それでもオーバーエンジニアリングの罪を犯したこのような構造をたくさん書くことができます。
ロバートハーヴェイ

1
@RobertHarvey trueですが、ここで示したサンプルコードがオーバーエンジニアリングの一種であることを意味していますか?委任は、iOS開発における一般的なパターンです。それはより多くのコードリストラではなく、再ようになるので、また、あなたはクラスの拡張機能を使用するかどうかは、-engineering(オーバー/)、その中にコードを変更しない
morbidhawk

1
私は同じファイルに多くの拡張機能を投げるこのパターンを見ていますが、これがどこから来たのかわかりません。一部の人々はすでにそれを悪用していて、同じファイル内の拡張機能に少しでもコードを勝手に投げ込んでいるようです。ときどきこれを行う正当な理由があると確信していますが、一部のプログラマーは、理由を理解せずにそれを行っているだけの印象を受けます。私はMARKを使用するよりもこの利点を探し続けています。-拡張機能をこのように使用する理由についての明確な情報源を見つけたいと思っています。
デヴィッド・ラリ

回答:


15

なぜ間接性のレベルが上がると言ったのかわかりません。たぶん、あなたはそれによって伝統的な意味とは異なる何かを意味します、これをすることによって作成される余分な間接性がないので。しかし、なぜそうするのですか?

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

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

とにかく、多くの場合、人々はファットビューコントローラーに不満を抱いています。ビューコントローラーをこのように分割すると、実際にビューコントローラーを薄くしなくても、整理しやすくなります。


モジュール性とはどういう意味かわかります。何が起こっているのかを理解すると、懸念を分離するきれいな方法のように見えました。私が考える間接性のレベルは、新しい目のセットに対するものです(そして、私はObj-cの方法から来ているのに偏っています)。基本クラスのどこかで定義されているコードが参照されているサブクラス化と同じレベルの間接参照を感じますが、それを見つけるのはもう少し難しいです。私は(少し間接コストで)組織的にそれが利益を追加することに同意する
morbidhawk

これは、Obj-Cのクラスカテゴリで以前に行われたと思います。私は決してそれらのファンではありませんでしたが、別のファイルが必要だと思います。今スウィフトに同じファイルに拡張子を保つことができるので、私はそのようにそれらを破ることにした場合、私はおそらくやるものだという
morbidhawk

2

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

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

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

Swiftでは、プロパティとメソッドはプロトコル宣言に実装されていません。didCopyText同じクラスの増分クラスを使用して、同じ実装でクラスにインクリメンタルなクラスを追加して、すべてのクラスに実装を書きたいと思うでしょう。繰り返しコード。そこで、Protocol Extensionsが役立ちます。

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

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


これを共有してくれてありがとう。この質問をしたとき、OO継承のいくつかの欠点については理解していませんでしたが、ここで説明しているのは、同じインターフェイスを強制するのではなく、そのインターフェイスに準拠するすべての実装クラスで再利用する素晴らしい方法ですオブジェクトからすべてを継承します。また、インターフェイス分離の原則に従っている場合は、必要に応じてプロトコルを分割して、実装クラスに必要のないインターフェイスのプロパティ/メソッドが含まれないようにすることができます。
-morbidhawk

1

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

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

これらの拡張子が本当に大きくない限り、私はそれらを別々のファイルに入れないでしょう。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.