確かに、順序集合は集合のより具体的なケースですが、なぜNSOrderedSet
はNSObject
ではなくNSSet
から継承するのでしょうか。
NSSet
のインターフェースを通過しましたが、その通り、順序集合は リスコフの置換原則 を満たしているように見えるため、NSSet
から継承できます。
これを破る小さな方法が1つあります:mutableCopy
。 mutableCopy
の戻り値はNSMutableSet
である必要がありますが、NSMutableOrderedSet
はNSOrderedSet
から継承する必要があります。両方を持つことはできません。
いくつかのコードで説明しましょう。まず、NSSet
とNSMutableSet
の正しい動作を見てみましょう。
NSSet* immutable = [NSSet set];
NSMutableSet* mutable = [immutable mutableCopy];
[mutable isKindOfClass:[NSSet class]]; // YES
[mutable isKindOfClass:[NSMutableSet class]]; // YES
ここで、NSOrderedSet
がNSSet
から継承し、NSMutableOrderedSet
がNSOrderedSet
から継承しているとしましょう。
//Example 1
NSOrderedSet* immutable = [NSOrderedSet orderedSet];
NSMutableOrderedSet* mutable = [immutable mutableCopy];
[mutable isKindOfClass:[NSSet class]]; // YES
[mutable isKindOfClass:[NSMutableSet class]]; // NO (this is the problem)
代わりにNSMutableOrderedSet
がNSMutableSet
から継承された場合はどうなりますか?次に、別の問題が発生します。
//Example 2
NSOrderedSet* immutable = [NSOrderedSet orderedSet];
NSMutableOrderedSet* mutable = [immutable mutableCopy];
[mutable isKindOfClass:[NSSet class]]; // YES
[mutable isKindOfClass:[NSMutableSet class]]; // YES
[mutable isKindOfClass:[NSOrderedSet class]]; // NO (this is a problem)
例1では、動作が異なるため、NSOrderedSet
を期待する関数にNSSet
を渡すことはできません。基本的に、これは下位互換性の問題です。
例2では、前者は後者を継承しないため、NSMutableOrderedSet
を期待する関数にNSOrderedSet
を渡すことはできません。
これはすべて、Objective-Cには多重継承がないため、NSMutableOrderedSet
がNSMutableSet
とNSOrderedSet
の両方から継承できないためです。これを回避する方法は、NSMutableSet
とNSOrderedSet
のプロトコルを作成することです。これは、NSMutableOrderedSet
が両方のプロトコルを実装できるためです。 Apple開発者は、追加のプロトコルがなくても簡単だったと思います。