3

このマルチトンの実装をobjective-cの「エレガント」と呼びますか?alloc私はプログラムで使用を「禁止」allocWithZone:しました。メモリを割り当てるかどうかの決定は、キーに基づいて行う必要があるためです。

2つのインスタンスのみで作業する必要があることは確かなので、マップの代わりに「switch-case」を使用しています。

#import "Multiton.h"

static Multiton *firstInstance = nil;
static Multiton *secondInstance = nil;

@implementation Multiton

+ (Multiton *) sharedInstanceForDirection:(enum KeyName)direction {

    return [[self allocWithKey:direction] init];
}

+ (id) allocWithKey:(enum KeyName)key {

    return [self allocWithZone:nil andKey:key];
}

+ (id) allocWithZone:(NSZone *)zone andKey:(enum KeyName)key {

    Multiton **sharedInstance;

    @synchronized(self) {

        switch (key) {
            case KEY_1:
                sharedInstance = &firstInstance;
                break;
            case KEY_2:
                sharedInstance = &secondInstance;
                break;
            default:
                [NSException raise:NSInvalidArgumentException format:@"Invalid key"];
                break;
        }
        if (*sharedInstance == nil)
            *sharedInstance = [super allocWithZone:zone];
    }

    return *sharedInstance;
}

+ (id) allocWithZone:(NSZone *)zone {

    //Do not allow use of alloc and allocWithZone
    [NSException raise:NSObjectInaccessibleException format:@"Use allocWithZone:andKey: or allocWithKey:"];
    return nil;
}

- (id) copyWithZone:(NSZone *)zone {

    return self;
}

- (id) retain {

    return self;
}

- (unsigned) retainCount {

    return NSUIntegerMax;
}

- (void) release {

    return;
}

- (id) autorelease {

    return self;
}

- (id) init {
    [super init];
    return self;
}

@end

PS:これがまだ機能するかどうかは試していませんが、きれいにコンパイルされています:)

4

3 に答える 3

3

シングルトンは悪い考えだと思いますが、これは約4倍恐ろしいように見えます。コードは非常に複雑で、微妙なバグを追いかけるのに数時間を費やすことができ、おそらくそれについて快適に感じることはないでしょう。それは良くないね。この忌まわしきものを捨てて、それほど考える必要のない他の方法でオブジェクトを配線する必要があります。

パターンが好きな場合は、ファクトリパターンに似たものを使用してオブジェクトを配線できます。Factoryは、これら2つのインスタンスを作成し、必要に応じてそれらを渡す処理を行います。そして、ファクトリーはマルチトンよりもはるかにシンプルになります。

@interface Factory : NSObject {
    Foo *foo1, *foo2;
}
@end

@implementation Factory

- (id) init {
    [super init];
    foo1 = [[Foo alloc] init];
    foo2 = [[Foo alloc] init];
    return self;
}

もちろん、両方のインスタンスを同時に作成する必要はありません。キャッシュ、遅延読み込みなど、好きなことを何でもできます。Foo重要なのは、コードとは別に、ライフタイム管理をファクトリに任せることFooです。その後、それははるかに簡単になります。¶必要な他のすべてのオブジェクトは、FooFactoryを介して作成および配線されFoo、セッターを介して受信されます。

@implementation Factory

- (id) wireSomeClass {
    id instance = [[SomeClass alloc] init];
    [instance setFoo:foo1];
    [instance setAnotherDependency:bar];
    return [instance autorelease];
}

これは、質問のコードよりもはるかに簡単です。

于 2010-03-24T17:26:12.693 に答える
2

allocをオーバーライドしないでください。クラスの以前に割り当てられたインスタンスを返すためにallocをオーバーライドする場合の問題は、+sharedInstanceが[[Multitonalloc] init] ...を呼び出すと、+ allocが古いインスタンスを返し、-initが再初期化することです。それ!ベストプラクティスは、キャッシュされたインスタンスを返す前に、-initをオーバーライドし、キャッシュルックアップを実行して[selfrelease]を呼び出すことです。

その余分な+allocのコストが本当に心配な場合(それほど多くはありません)、+ sharedInstanceでキャッシュルックアップを実行し、すべてのクライアントが+ sharedInstanceを介してインスタンスにアクセスするようにして、余分なallocを回避します。

于 2010-03-24T13:50:04.650 に答える
0

注文のポイント:インスタンスが2つしかない、またはインスタンスが2つ必要になることをどのように知っていますか?(または2つのインスタンスが必要ですか?)正確には、「マルチトン」を持つことのポイントは何ですか?(そしてそれは一言でもありますか?)

于 2010-03-24T12:00:33.873 に答える