سؤال

هل تسمي هذا التنفيذ من multiton في "الهدف" الأنيق؟ لدي استخدام "غير مسموح به" برمجيًا alloc و allocWithZone: لأن قرار تخصيص الذاكرة أو عدم تخصيصه يجب القيام به بناءً على مفتاح.

أعلم على وجه اليقين أنني بحاجة إلى العمل مع حالتين فقط ، لذلك أنا أستخدم "حالة التبديل" بدلاً من الخريطة.

#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

ملاحظة: لم أجرب ما إذا كان هذا يعمل حتى الآن ، ولكن تجميعه بشكل نظيف :)

هل كانت مفيدة؟

المحلول

أجد أن المفردات فكرة سيئة وهذا يبدو حوالي أربع مرات فظيعة. الكود معقد للغاية ، يمكنك التأكد من قضاء ساعات قليلة لطيفة في مطاردة الأخطاء الدقيقة فيه وربما لن تشعر بالراحة حيال ذلك. هذا ليس جيدا. يجب أن ترمي هذا رجسًا بعيدًا وتوصيل الأشياء معًا بطريقة أخرى لا تتطلب الكثير من التفكير.

إذا كنت تحب الأنماط ، فيمكنك استخدام شيء أقرب إلى نمط المصنع لتسليم كائناتك. سيهتم المصنع بإنشاء هاتين الحالتين ويمررانهما أينما كان الحاجة. وسيكون المصنع أكثر بساطة من Multiton:

@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 الشفرة. ثم يصبح الأمر أسهل بكثير. ¶ جميع الكائنات الأخرى التي تحتاج Foo سيتم إنشاؤها وتسلكها من خلال المصنع وسيحصل عليها Foo من خلال setter:

@implementation Factory

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

هذا كله أكثر وضوحا ثم الرمز من سؤالك.

نصائح أخرى

لا تتغلب على التخصيص. المشكلة في تجاوز التخصيص لإرجاع مثيل تم تخصيصه مسبقًا للفصل ، كما تفعل ، هي أنه عندما يقوم +sharedinstance [[[Multiton inist] init] ... -init سوف يعيد تخصيصه! أفضل الممارسات هي تجاوز -إجراء البحث عن ذاكرة التخزين المؤقت والاتصال [الإصدار الذاتي] قبل إعادة المثيل المخزنة مؤقتًا.

إذا كنت هل حقا تشعر بالقلق إزاء تكلفة هذا التخصيص الإضافي +(ليس كثيرًا) ، يمكنك أيضًا البحث عن ذاكرة التخزين المؤقت في +sharedInstance ومن ثم تأكد من الوصول إلى جميع عملائك من خلال +sharedInstance لتجنب التخصيص الإضافي.

نقطة الطلب: كيف تعرف أنه سيكون لديك حالتان فقط ، أو تحتاج إلى حالتين؟ (أو تريد أن يكون لديك حالتان؟) ما هو بالضبط نقطة من وجود "multiton"؟ (وهل هذه كلمة؟)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top