編集:Objective-Cの制限について私が責任を負っていると感じる人もいるため、変更が追加されました。
短い答え:できません。Objective-C には、Ruby mixin に相当するものはありません。
やや短めの答え: Objective-C には、ほぼ間違いなく同じ趣向を持つものがあります: プロトコルです。プロトコル (他の言語ではインターフェース) は、そのプロトコルが実装を約束しているクラスが採用する一連のメソッドを定義する方法です。ただし、プロトコルは実装を提供しません。この制限により、プロトコルを Ruby ミックスインとまったく同じものとして使用することができなくなります。
さらに短い答え:ただし、Objective-C ランタイムには、言語の動的機能を操作できる API が公開されています。次に、言語の外に出ますが、デフォルトの実装を持つプロトコル (具体的なプロトコルとも呼ばれます) を持つことができます。ウラジミールの答えは、それを行う1つの方法を示しています。その時点で、Ruby ミックスインは問題ないように思えます。
ただし、それをお勧めするかどうかはわかりません。ほとんどの場合、ランタイムでゲームをプレイしなくても、他のパターンが適しています。たとえば、混合メソッド ( is- a の代わりにhas-a ) を実装するサブオブジェクトを持つことができます。ランタイムをいじっても問題ありませんが、2 つの欠点があります。
読者は言語以上の知識を必要とするため、コードが読みにくくなります。もちろん、コメントすることもできます (コメントする必要があります) が、必要なコメントは実装上の欠陥と見なされる可能性があることを覚えておいてください。
その言語の実装に依存します。確かに、Apple プラットフォームは Objective-C の最も一般的なプラットフォームですが、ランタイムが異なる Cocotron や GnuStep (または Etoilé) を忘れないでください。これらは、その点で Apple と互換性がある場合とない場合があります。
補足として、カテゴリはクラスに状態 (インスタンス変数) を追加できないことを以下に述べます。ランタイム API を使用することで、その制限も解除できます。ただし、これはこの回答の範囲を超えています。
長い答え:
Objective-C の 2 つの機能が候補のように見えます: カテゴリとプロトコルです。質問を正しく理解していれば、カテゴリはここでは正しい選択ではありません。適切な機能はプロトコルです。
例を挙げましょう。クラスの束に「歌う」と呼ばれる特定の能力を持たせたいとします。次に、プロトコルを定義します。
@protocol Singer
- (void) sing;
@end
これで、独自のクラスのいずれかが次の方法でプロトコルを採用することを宣言できます。
@interface Rectangle : Shape <Singer> {
<snip>
@end
@interface Car : Vehicle <Singer> {
<snip>
@end
プロトコルを採用することを宣言することにより、sing
メソッドの実装にコミットします。例えば:
@implementation Rectangle
- (void) sing {
[self flashInBrightColors];
}
@end
@implementation Car
- (void) sing {
[self honk];
}
@end
次に、これらのクラスをたとえば次のように使用します。
void choral(NSArray *choir) // the choir holds any kind of singer
{
id<Singer> aSinger;
for (aSinger in choir) {
[aSinger sing];
}
}
配列内の歌手は、共通のスーパークラスを持つ必要がないことに注意してください。また、クラスはスーパークラスを 1 つしか持つことができませんが、多くのプロトコルを採用していることにも注意してください。最後に、コンパイラによって型チェックが行われることに注意してください。
実際には、プロトコル メカニズムは mixin パターンに使用される多重継承です。プロトコルは新しいインスタンス変数をクラスに追加できないため、多重継承は大幅に制限されます。プロトコルは、採用者が実装する必要があるパブリック インターフェイスのみを記述します。Ruby モジュールとは異なり、実装は含まれません。
それが一番です。ただし、カテゴリについて言及しましょう。
カテゴリは、山かっこではなく、かっこの間で宣言されます。違いは、サブクラス化せずに既存のクラスを拡張するためにカテゴリを定義できることです。システムクラスに対してもそうすることができます。ご想像のとおり、カテゴリを使用して mixin に似たものを実装することができます。そして、それらは通常、(継承階層の典型的なルート) へのカテゴリとして長い間そのように使用され、NSObject
「非公式」プロトコルと呼ばれるほどでした。
1-コンパイラによる型チェックは行われず、2-プロトコルメソッドの実装はオプションであるため、非公式です。
現在、カテゴリをプロトコルとして使用する必要はありません。特に、正式なプロトコルでは、メソッドの一部がキーワードでオプションである、@optional
または で必須 (デフォルト) であると宣言できるためです@required
。
カテゴリは、ドメイン固有の動作を既存のクラスに追加するのに依然として役立ちます。NSString
そのための共通のターゲットです。
また、ほとんどの機能 (すべてではないにしても) が実際にはプロトコルNSObject
で宣言されていることを指摘するのも興味深いことです。NSObject
これは、すべてのクラスに共通のスーパークラスとして使用することは実際には魅力的ではないことを意味しますNSObject
が、これは歴史的な理由から今でも一般的に行われています.そうすることに欠点がないからです. ただし、 などの一部のシステム クラスはNSProxy
ではありません NSObject
。