クラス1とクラス2が "共有オブジェクト"の同じインスタンスを使用することを確実にするために、多くのオプションがあります。
- は明確ではなく、インスタンス自身を作成するために、クラス1とクラス2を可能にするよりも、外部からのクラス1とクラス2の同じインスタンスを渡します。または
- Functionsクラスにシングルトン初期化子を指定し、Class1とClass2がこれを使用することを確認します。または
- レジストリパターンと呼ばれるデザインパターンを使用して、クラス1とクラス2が関数クラスのインスタンスをレジストリから取得するようにします。または
- 依存性注入(複合)を使用します。
Functions *funcs = [[Functions alloc] init];
Class1 *obj1 = [[Class1 alloc] initWithFunctions:funcs];
Class2 *obj2 = [[Class2 alloc] initWithFunctions:funcs];
/* or alternatively use setters after initialization */
シナリオ(2)は次の最も簡単であり、非常に一般的です:
シナリオ(1)は、まさにこのように書きますので、理解するのが最も簡単です。 Cocoaは、多くのクラスにシングルトン初期化子を提供します。イニシャライザのプレフィックスとして+shared...
が表示されている場合は、おそらくシングルトンが返されます。
@implementation Functions
+(id)sharedFunctions {
static Functions *sharedFunctions = nil;
@synchronized(self) {
if (sharedFunctions == nil) {
sharedFunctions = [[self alloc] init];
}
return sharedFunctions;
}
}
@end
静的変数は、あなたが遅延し、それが(1回だけ発生)初期値だのチェックを使用して、その中にオブジェクトのインスタンスをロードすることができることを意味しており、一度だけ初期化されます。このメソッドへの以降の呼び出しでは、同じインスタンスが返されます。
Functions *f1 = [Functions sharedFunctions];
Functions *f2 = [Functions sharedFunctions];
/* f1 == f2; */ // always
オプション(3)は、他の言語と比較して客観的なCではあまり見られず、シングルトンと同じ目標を達成します。そのアイデアは、あなたがキーで調べることができるオブジェクトの辞書を持っているということです。レジストリ内の項目へのアクセスが必要なものはすべて、レジストリに独自のインスタンスを要求するだけです。通常、レジストリ自体はシングルトンになります。
オプション(4)は、実際には非常に洗練されたソリューションであり、複雑さを増すだけで多くの利点があります。依存関係が常に緩やかに結合されていることが保証されていること(つまり、実装をスワップアウトし、独立した単体テストを独立させるほうがずっと簡単です)という利点があります。複雑さは、必要なもののインスタンスを取得するための非標準的なメカニズムに由来します。
依存性注入は、オブジェクトがそれ自身の依存関係をインスタンス化しないというアイデアを中心に展開されています。これらの依存関係を提供するために他のものに頼るのではなく、それは依存性注入容器として知られているものです。依存性注入コンテナは事実上レジストリパターンの最上位レイヤーです。これは、コンテナがあらかじめ作成された依存関係のインスタンスを保持するか、新しいインスタンスをインスタンス化する方法を知るためです。
最も単純なケースでは、依存性注入はまさに私がオプション(1)で示したものです。これを達成するために依存性注入コンテナは必要ありません。
複雑さのレベルをシフトすると、依存性注入はDIコンテナのコンセプトをもたらします。これは、既存のデザインパターン(レジストリ、オプション(3)、シングルトン
DIコンテナを完全に実装することは、おそらくこの質問の範囲を超えていますが、パブリックインターフェイスの観点からは、 1つの実装は次のようになります:
DIContainer *container = [DIContainer sharedContainer];
[container registerClass:[ClassA class]];
[container registerClass:[ClassB class]];
[container registerDependentProperty:@selector(setClassA:)
withInstanceOf:[ClassA class]
forClass:[ClassB class]];
ClassB *obj = [container makeInstanceOfClass:[ClassB class]];
NSLog(@"ClassB's -classA type = %@", [[obj classA] class]);
私はちょうど私の頭の上からそれを打ちました。この投稿の真ん中ですので、それが100%正確であるとは思わないでください。コンテナは、ClassBのインスタンスを初期化するときに、ClassA
のインスタンスを使用して-setClassA:
を呼び出す必要があります。コンテナに定義されているルールに従って初期化されます(この場合、ClassA
の依存関係はありません。プレーンなインスタンスを返すあなたはもっと離れて、この答えから何も取っていない場合は、単に覚えて
オプション(1)及び(2);。)
お元気ですか、本当に便利です。私はオプション2に行って、うまくいきます。オプション3と4は私の頭の中を少し行きましたが、私は少し眠った後、明日にそれらを読んでいきます。午前中にもう少し意味をなさないかもしれません。しかし、助けてくれてありがとう、非常に便利です。 :-D – Baza207
問題はない、私はオプション(2)で行くあなたの選択は良いものだと思う。オプション(1)は、テストするのが難しい(不正なテスト環境)ため、多くの開発者の間でシングルトンが多少悪い評判を持っているため、「技術的に」最高です。しかし、正しく使用しても問題ありません。実際、Objective-Cは他の言語と同じように単一の排他的初期化子/コンストラクタを持っていないので、シングルトンは100%強制されていないので、どのような場合でもテストで回避することができます。オプション3は非常に簡単ですが、オプション(4)は経験豊かな開発者でさえ混乱させるテーマです。 – d11wtq
私はこの質問が古いことを知っていますが、これは完全に私を助けました。 +1 –