2

私はObjective-Cを学び、オブジェクト指向デザインのスキルを少し向上させるための電卓アプリを作成しています。よりMVCのようなことをするために、私は実際の電卓関連のコードをViewControllerから分離しました。すべてのアクションについて、View Controllerが行うほとんどすべてのことは、「モデル」にそのアクション用の操作を実行するように指示することです。

つまり、次のように、基本的にアクションをモデルに転送するだけの一連のメソッドが得られます。

- (IBAction)clearAll:(id)sender {
    [self.model clearAll];
}

- (IBAction)clearDisplay:(id)sender {
    [self.model clearDisplay];
}

- (IBAction)clearMemory:(id)sender {
    [self.model clearMemory];
}

- (IBAction)storeMemory:(id)sender {
    [self.model storeMemory];
}

- (IBAction)addMemory:(id)sender {
    [self.model addMemory];
}

- (IBAction) subtractMemory:(id)sender {
    [self.model subtractFromMemory];
}

- (IBAction)recallMemory:(id)sender {
    [self.model recallMemory];
}

これまでのところ、Objective-Cはメッセージを動的に転送することで非常に柔軟に見えます。これらの方法は、かなり簡単に自動化されているように見えるのに十分似ています。彼らは本当にそこにいる必要がありますか?または、特定のメッセージをモデルに渡すようにコントローラーに指示する繰り返しの少ない方法がありますか(理想的には、sender引数を取り除いている間)?

私は少し調べてセレクターとを使っていくつかのことを試してきましたが、ボタンをアクションに接続するためのすべてのマーカーNSInvocationを取り除くことで、InterfaceBuilderを台無しにするようです。(IBAction)(これらの場合、ビューがコントローラーがモデルに転送していることを認識または気にする必要がない場合は、この方法をお勧めします。)

それで、より反復的および/またはハッキーな方法はありますか?それとも、トラブルの価値はありませんか?(または、そもそもそれは悪い考えですか?それとも、これはモデルにやりすぎをさせようとしているのですか?または...)

4

2 に答える 2

4

言語の動的機能を使用できます。

Objective-Cランタイムプログラミングのドキュメントから

メッセージ内のセレクターに一致するメソッドがないためにオブジェクトがメッセージに応答できない場合、ランタイムシステムはオブジェクトにを送信して通知しますforwardInvocation

したがって、あなたの場合、次のようにforwardinvocationメソッドを実装できます。

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    if ([self.model respondsToSelector:[anInvocation selector]])
        [anInvocation invokeWithTarget:self.model];
    else
        [super forwardInvocation:anInvocation];
}

メソッドのシグネチャも統一する必要があります。パラメータを削除するかsender、モデルのメソッドに追加します。そうしないと、パラメータrespondsToSelectorが返さNOれ、メソッドは呼び出されません。

この場合forwardInvocation、ディスパッチャーとして機能し、コントローラーによって実装されていないすべてのメッセージをself.modelオブジェクトに送信しようとします。これがセレクターに応答しない場合は、が呼び出さsuperれ、認識されないセレクター例外が発生する可能性があります。

個人的には、自分が何をしているのかを正確に把握し、そのような機能を使いすぎないようにしたほうがよいとはいえ、非常にエレガントだと思います。

于 2012-12-31T01:00:04.300 に答える
4

Gabrieleが提案したことを実行できます。これは、ObjCがいかに動的であるかを示す一例ですが、回避したほうがよいでしょう。Gabrieleが言ったように、あなたは自分が何をしているのかを正確に知り、そのような機能を使いすぎないようにしたほうがよいでしょう。そして、それはしばしば、そのような機能が価値があるよりも厄介である可能性が高いことを示しています。

現実には、電卓アプリケーションは、Model-View-Controllerパターンに固有の分離を実現するために非常に工夫されています。あなたが言うように、それは学習アプリです。

実際には、これほど単純なアプリケーションはありません。コントロールレイヤーが上記の機能をモデルに盲目的に転送するボタンのフィールドが存在することはめったにありません。

代わりに、その制御層には、さまざまなアクションの自動化から検証(場合によってはモデルのクエリによる)、さまざまなアクションに応じたUI状態の更新まで、あらゆることを実行できるあらゆる種類のビジネスロジックがあります。

このコードはプロジェクトの非常に早い段階から存在する可能性が高いため、一般的な転送メカニズムはすぐに完全に使用されなくなります。

同様に、そのような転送メカニズムは、デバッグに関しては苦痛に満ちた漏斗になります。ブレークポイントをドロップする具体的な場所はもうありませんが、条件を追加する必要があります。また、特定のメソッドを呼び出したり実装したりする可能性のあるすべての場所を簡単に見つける方法もありません。また、制御フローの追跡がより困難になります。

反復的なボイラープレートコードがたくさんある場合は、反復性を減らすために巧妙な動的メカニズムを注入する必要があるという兆候というよりも、アーキテクチャに欠陥がある可能性が高いという兆候です。

同様に、電卓アプリを肉付けし続けるとしたら、アプリの他のすべての機能と比較して、これらの反復的なメソッドを実行するためにコーディング時間のどのくらいが費やされたでしょうか。おそらく、ごくわずかであり、デバッグが簡単で便利なため、前述の反復的な方法で大幅なメンテナンスコストが発生する可能性はほとんどありませんが、巧妙で動的なちょっとしたトリック(これは非常にクールであり、他のコンテキストでそれを探索してください)は、「ええと、私はここで何を考えていたのですか?!」しばらくして。

于 2012-12-31T01:30:46.527 に答える