17

多くのブログ、フォーラム エントリ、およびいくつかの Apple ドキュメントを読んだ後でも、Objective-C で広範なサブクラス化を行うことが賢明かどうかはまだわかりません

たとえば、次のケースを考えてみましょう。

要素の多いパズル ゲームを開発しているとします。これらの要素はすべて、ある程度同じ動作を共有します。次に、要素のコレクション内で、要素のさまざまなグループが同等の動作を共有し、グループをグループから区別するなど...

それで、何を何から継承するかを決定した後、忘却からサブクラス化することにしました。そして、なぜ私はすべきではないのですか? このモデルで一般的な動作を簡単に微調整できることを考えると、OOP の目的を達成できたと思います。

しかし、- これが私の質問の源です- Apple は、サブクラス化を支持してデリゲート、データ ソース メソッド、非公式プロトコルの使用について言及しています。本当に頭がおかしくなるのはなぜですか?

2つのキャンプがあるようです。サブクラス化に賛成の人、そうでない人。どうやら個人の好みによるようです。大規模にサブクラス化することと、大規模にサブクラス化しないことの長所と短所は何ですか?

まとめとして、私の質問は簡単です。私は正しいですか? そして、なぜ、またはなぜではないのですか?

4

9 に答える 9

12

委任は、合成手法を使用して、他の方法ではサブクラス化するコーディングのいくつかの側面を置き換える手段です。そのため、多くのことを行う方法を知っている1つの大きなものが必要な、または特殊なオブジェクトのネットワークが緩い場合(非常にUNIXのような責任モデル)、手元にあるタスクの古くからの質問に要約されます。

デリゲートとプロトコルの組み合わせを使用すると(デリゲートが実行できるはずのことを定義するため)、動作の柔軟性とコーディングの容易さが大幅に向上します。リスコフの置換原則に戻ると、サブクラス化する場合は注意が必要です。クラス全体のユーザーが予期しないことをするようなことは何もしません。しかし、単にデリゲートオブジェクトを作成している場合は、責任を負う必要がはるかに少なくなります。実装するデリゲートメソッドは、1つのプロトコルが要求することを実行するだけであり、それ以上は気にしません。

サブクラスを使用する理由はまだたくさんあります。多くのクラス間で動作と変数を本当に共有している場合は、サブクラスに多くの意味があるかもしれません。ただし、デリゲートの概念を利用できる場合は、多くの場合、設計者が予期していなかった方法でクラスを拡張または使用しやすくなります。

私は非公式のプロトコルよりも正式なプロトコルのファンである傾向があります。なぜなら、正式なプロトコルは、クラスがあなたを代理人として扱うメソッドを持っていることを確認するだけでなく、プロトコルの定義があなたのことを文書化するための自然な場所だからです。それらのメソッドを実装するデリゲートに期待します。

于 2009-05-10T06:02:34.070 に答える
10

個人的には、次のルールに従います。リスコフの置換原理を尊​​重する場合、サブクラスを作成できます。

于 2009-05-09T22:25:43.950 に答える
7

サブクラス化には利点がありますが、いくつかの欠点もあります。原則として、実装の継承を避け、代わりにインターフェイスの継承と委譲を使用します。

私がこれを行う理由の 1 つは、実装を継承するときに、メソッドをオーバーライドしてもメソッド (文書化されていない契約の場合もあります) を守らないと、問題が発生する可能性があるためです。さらに、メソッドは任意のレベルでオーバーライドまたは実装できるため、実装の継承を使用してクラス階層を歩くことは難しいと思います。最後に、サブクラス化する場合、インターフェースを広げることしかできず、狭めることはできません。これは、漏れやすい抽象化につながります。この良い例は、java.util.Vector を拡張する java.util.Stack です。スタックをベクターとして扱うことはできません。そうすることで、コンシューマーはインターフェイスを回避することしかできなくなります。

他の人は、リスコフの置換原理に言及しています。これを使用すれば確かに java.util.Stack の問題は解消されると思いますが、クラスが持つべきメソッドのみを確​​実に取得するために、非常に深いクラス階層につながる可能性もあります。

代わりに、インターフェイスの継承では、インターフェイスが互いに拡張する必要がほとんどないため、基本的にクラス階層はありません。クラスは、必要なインターフェイスを実装するだけなので、消費者は正しい方法で処理できます。さらに、実装の継承がないため、これらのクラスのコンシューマーは、親クラスでの以前の経験により、動作を推測しません。

とはいえ、結局、どちらに行っても大差ありません。どちらも完全に受け入れられます。それは実際には、あなたがより快適に感じていることと、あなたが取り組んでいるフレームワークが何を奨励しているのかという問題です. 古いことわざにあるように、「ローマにいるときはローマ人がするように」。

于 2009-05-10T05:26:26.123 に答える
6

There's nothing wrong with using inheritance in Objective-C. Apple uses it quite a bit. For instance, in Cocoa-touch, the inheritance tree of UIButton is UIControl : UIView : UIResponder : NSObject.

I think Martin hit on an important point in mentioning the Liskov substitution principle. Also, proper use of inheritance requires that the implementer of the subclass has a deep knowledge of the super class. If you've ever struggled to extend a non-trivial class in a complex framework, you know that there's always a learning curve. In addition, implementation details of the super class often "leak through" to the subclass, which is a big pain in the @$& for framework builders.

Apple chose to use delegation in many instances to address these problems; non-trivial classes like UIApplication expose common extension points through a delegate object so most developers have both an easier learning curve and a more loosely coupled way to add application specific behavior -- extending UIApplication directly is rarely necessary.

In your case, for your application specific code, use which ever techniques you're comfortable with and work best for your design. Inheritance is a great tool when used appropriately.

I frequently see application programmers draw lessons from framework designs and trying to apply them to their application code (this is common in Java, C++ and Python worlds as well as Objective-C). While it's good to think about and understand the choices framework designers made, those lessons don't always apply to application code.

于 2009-05-09T23:24:54.977 に答える
4

一般に、やりたいことを実行するデリゲートなどが存在する場合は、APIクラスのサブクラス化を避ける必要があります。独自のコードでは、サブクラス化の方が優れていることがよくありますが、実際には目標によって異なります。APIを提供する場合は、サブクラス化を想定するのではなく、デリゲートベースのAPIを提供する必要があります。

APIを扱う場合、サブクラス化にはより多くの潜在的なバグがあります。クラス階層内のいずれかのクラスが、追加したものと同じ名前の新しいメソッドを取得した場合は、ブレークを作成します。また、便利な/ヘルパー型の関数を提供している場合、将来、サブクラス化していた実際のクラスに同様の関数が追加される可能性があります。これはより効率的かもしれませんが、オーバーライドによって非表示になります。

于 2009-05-09T23:16:12.657 に答える
4

Apple のドキュメント「Cocoa プログラムへの動作の追加」をお読みください。「Cocoa クラスからの継承」セクションの 2 番目の段落を参照してください。Apple は、サブクラス化がアプリケーション固有の動作をフレームワークに追加する主要な方法であることを明確に述べています ( FRAMEWORKに注意してください)。
MVC パターンは、サブクラスまたはサブタイプの使用を完全に禁止しているわけではありません。少なくとも、私は Apple や他の人からこの推奨事項を見たことがありません (見逃した場合は、これに関する適切な情報源を教えてください)。アプリケーション内でのみ API クラスをサブクラス化する場合は、先に進んでください。誰もあなたを止めませんが、クラス/API 全体の動作を壊さないように注意してください。サブクラス化は、フレームワーク API の機能を拡張する優れた方法です。Apple IOS フレームワーク API 内でも多くのサブクラス化が見られます。開発者は、実装が十分に文書化され、別の開発者によって誤って複製されないように注意する必要があります。アプリケーションが、再利用可能なコンポーネントとして配布する予定の API クラスのセットである場合、まったく別の球技です。

私見ですが、ベスト プラクティスとは何かを尋ねるのではなく、まず関連するドキュメントをよく読み、実装してテストしてください。ご自身で判断してください。あなたが何をしようとしているのか、あなたが一番よく知っています。他の人 (私や他の多くの人のように) は、ネット上のさまざまな情報源から情報を読み、用語を投げかけるだけで簡単にできます。あなた自身の裁判官になってください、それはこれまで私のために働いてきました.

于 2012-10-13T19:24:45.760 に答える
3

I really think it depends on what you're trying to do. If the puzzle game you describe in the example really does have a set of unique elements that share common attributes, and there's no provided classes - say, for example, "NSPuzzlePiece" - that fit your needs, then I don't see a problem with subclassing extensively.

In my experience, delegates, data source methods, and informal protocols are much more useful when Apple has provided a class that already does something close to what you want it to do.

For example, say you're building an app that uses a table. There is (and I speak here of the iPhone SDK, since that's where I have experience) a class UITableView that does all the little niceties of creating a table for interaction with the user, and it's much more efficient to define a data source for an instance of UITableView than it is to completely subclass UITableView and redefine or extend its methods to customize its behavior.

Similar concepts go for delegates and protocols. If you can fit your ideas into Apple's classes, then it's usually easier (and will work more smoothly) to do so and use data source, delegates, and protocols than it is to create your own subclasses. It helps you avoid extra work and wasting time, and is usually less error-prone. Apple's classes have taken care of the business of making functions efficient and debugging; the more you can work with them, the fewer mistakes your program will have in the long run.

于 2009-05-09T23:18:57.910 に答える
2

ADC がサブクラス化に対して「反対」に重点を置いているという私の印象は、オペレーティング システムがどのように進化してきたかという遺産と関係があります... 昔 (Mac Classic 別名 os9)、C++ がほとんどの Mac ツールボックス、サブクラス化への主要なインターフェイスでした。は、プログラマがありふれた OS 機能の動作を変更するためのデファクト スタンダードでした (実際、これは時々首の痛みであり、すべての変更が予測どおりに動作し、変更されないように非常に注意する必要がありました)。標準的な動作を破る)。

そうは言っても、サブクラス化に対するADCの強調の私の印象は、継承なしでアプリケーションのクラス階層を設計するためのケースを提示していませんが、代わりに、物事を行う新しい方法(つまりOSX)では、ほとんどの場合、より適切な方法があることを指摘するためにサブクラス化する必要なく、標準の動作をカスタマイズすることを意味します。

したがって、パズル プログラムのアーキテクチャをできる限り堅牢に設計し、適切と思われる継承を活用してください。

あなたのクールな新しいパズルアプリケーションを見るのを楽しみにしています!

|K<

于 2009-05-11T13:45:16.510 に答える
0

実際、Apple は Objective-C によるサブクラス化を受動的に思いとどまらせているようです。

実装よりも構成を優先することは、OOP 設計の公理です。

于 2014-01-19T10:51:01.707 に答える