0

デリゲートについて質問されましたが、正しい答えについて疑問がありました。

独自のプロトコルを作成する場合、デリゲートを使用するか、単にクラスをインスタンス化して単純なメソッドを呼び出すかの違いは何ですか?

私は考えました:デリゲートを使えば、わざわざ新しいクラス全体をインスタンス化する必要はなく、デリゲートをクラスの外に設定して、「デリゲート」でメソッドを呼び出すだけです。無制限のインポートを回避するためにデリゲートを使用することも良いことですか? classA が classB をインポートする場合、デリゲートを使用する代わりにクラスをインスタンス化すると、classB も classA をインポートし、クラッシュの原因になりますか?

独自のプロトコル/デリゲートを作成する場合、他に正当な理由はありますか?

共有してくれてありがとう

4

3 に答える 3

1

デリゲートの主な利点は、実行時にオブジェクトの動作を変更できることだと思います。また、機能領域間の分離を強制するのにも役立ちます。

具体的な例を見てみましょう: NSTableViewのデータ ソース。 NSTableViewOS X のテーブルの UI 実装を提供します。データ ソース デリゲートは、データを保持してテーブルに入力する機能を提供します。

私が Objective-C に来て C++ と Java でプログラミングする前の昔は、さまざまなテーブル ビューを作成するためにサブクラス化されるデータを管理するためのいくつかの保護されたメソッドを UI クラスに持たせることで、テーブル ビューを実装していました。

このアプローチは完全に有効ですが、データを管理する機能と表示する機能が混同されており、あまり柔軟ではありません。ウィジェット X は、特定の方法でデータにアクセスするテーブル ビューであると言ったら、それはすべて確定です。ウィジェット X に別の方法でデータを取得させたい場合は、その柔軟性を UI クラスに組み込むか、それを破棄して別のサブクラスから再作成する必要があります。

一方、デリゲート パターンNSTableViewでは、単純な割り当てとリロードでデータ ソースを完全に変更できます。また、UI クラスはデータ処理コードで汚染されず、データ処理クラスは UI 処理コードで汚染されません。

プロトコルを使用せずにデリゲートを実行できます。実際、10.5 より前のバージョンの Cocoa では、これは例外ではなく標準でしたが、プロトコルを使用してデリゲート API を定義すると、デリゲート実装のエラー チェックに対するコンパイラ サポートが得られます。そして最低限のドキュメント。

于 2012-08-15T11:23:33.677 に答える
1

さて、例を見てください。

ウィンドウが行っていることの一部としてたまたまウィンドウを表示する「何か」があるとします。デリゲートまたは同様のセットアップがなければ、ウィンドウを処理するには「ウィンドウ」のサブクラスである必要があり、他の操作を処理するには他の何かのサブクラスである必要があります。したがって、それは不可能であるか、あらゆる種類の多重継承の奇妙さに陥ります。

したがって、おそらく何でもサブクラスを作成し、「ウィンドウ」のサブクラスを作成し、両方のオブジェクトをインスタンス化し、それらに何らかの方法で通信させることになります。これはまさにデリゲートが行うことですが、あらゆる種類のことに対して何度も何度も行う必要があります。たとえば、10 個のボタンが含まれるウィンドウを想像してみてください。各ウィンドウには、実際のクラスで "ButtonXClicked" を呼び出すこと以外は、実際にはそれほど多くのことを行わないボタンのサブクラスが必要です。繰り返しになりますが、ここで再実装された「デリゲート」を参照してください (はい、Cocoa ではデリゲートではありません。それがターゲット/アクションになります。しかし、デリゲートとそれほど違いはありません)。

したがって、デリゲートは、派生クラスによって暗示されるような「種類の」関係を実際には持たないオブジェクトを接続するのに非常に便利です。

また、オブジェクトを作成してそれを返す何かがある場合のように、「他の場所で作成された」オブジェクトを接続することもできます。実際にはサブクラスをそこに置き換えることはできませんが、API では「 setDelegate:" のようなものを使用して、そのオブジェクトをアプリケーションに接続します。

デリゲートの方が適切な場合もあれば、サブクラスの方が優れている場合もあり、それがあまり重要でない場合もあります。

于 2012-08-15T10:40:55.000 に答える
0

問題は一般化の1つです。無制限のインポートは避けるのが最善です。

このシナリオを想像してみてください。(KDTimerと呼ばれるクラスからの)タイマーが実行され、ある時点で期限切れになります。次に、3つのゲームモードA、B、C(すべて3つの異なるクラスに対応)で使用します。これで、ゲームモードが異なれば、タイマーの有効期限に対する反応も異なります。あなたが得る違いは次のとおりです:

委任:

KDTimerでプロトコルを定義し、a、b、またはcをそのデリゲートに設定し(実際には、a、b、またはcはそれ自体をタイマーデリゲートに設定します)、

-(void) increaseProgress {
//incrementProgress
if(self.progress>=1) 
[_delegate timeExpired];
}

そして、あなたは金色です。

非デリゲート:

#import "A"
#import "B"
#import "C"

@synthesize a,b,c;
-(void) increaseProgress {
//incrementProgress
if(self.progress>=1) 
[self.a timeExpired];
[self.b timeExpired];
[self.c timeExpired];
//we don't really know which instance should be messaged
}

重要なのは、デリゲートを使用しないと複雑なコードになる可能性があるということです。デリゲートを使用すると、より再利用可能なコンポーネントが得られます。タイマーはゲームモードについて知る必要はありません。タイマーが期限切れになったことを通知しようとしているだけです。

于 2012-08-15T10:31:59.157 に答える