Справка по шаблонам проектирования: пул уникальных объектов - PullRequest
1 голос
/ 11 мая 2009

Я ищу шаблон проектирования для управления пулом объектов. Поток может запросить объект, в моем случае объект, представляющий удаленный хост.

Если хост-объект не существует, он создается, добавляется в пул и возвращается ссылка.

Если другой поток или объект запрашивает тот же (удаленный хост) объект, ему тоже дается ссылка. Если запрашивается другой удаленный хост, он создается и добавляется в «пул» объектов.

Как только хост-объект больше не нужен ни одному потоку или объект удаляется, он сам формирует пул.

  1. Есть шаблон для этого и как его зовут?
  2. Я буду реализовывать это в Objective-C, любая конкретная помощь будет полезна.

Ответы [ 5 ]

5 голосов
/ 11 мая 2009

Альтернативой использованию NSMapTable (который недоступен, например, на iPhone) является использование эквивалентов CoreFoundation. Они могут содержать обычные не сохраненные указатели. Тем не менее, вам все равно нужно извлечь что-то из этого списка, но это легко сделать с помощью метода -dealloc объекта.

Одна из возможностей - использование CFSet. Для этого потребуется, чтобы все ваши объекты правильно реагировали на -isEqual: и -hash, чтобы набор мог определить, точно ли объект уже присутствует.

Например (обратите внимание, что я не скомпилировал это, но это должно быть как минимум на 90% правильно):

static id __uniqueObjects = nil;    // GC uses NSHashTable, non-GC uses NSSet (inited using CFSet APIs)

@interface MyHost : NSObject
{
    NSURL * _hostURL;
}

@property (nonatomic, readonly) NSURL * hostURL;

+ (MyHost *) uniqueHost: (MyHost *) aHost;
+ (void) removeUniqueHost: (MyHost *) aHost;     // only used in non-GC environment

- (id) initWithURL: (NSURL *) hostURL;

@end

@implementation MyHost

- (id) initWithURL: (NSURL *) hostURL
{
    self = [super init];
    if ( self == nil )
        return ( nil );

    // use copy, because NSURL implements NSCopying protocol
    _hostURL = [hostURL copy];

    // if there's a version around already, release this instance
    MyHost * result = [[self class] uniqueHost: self];
    if ( result != self )
    {
        // set _hostURL to nil so we don't inadvertently remove anything from uniqueing table in -dealloc
        [_hostURL release];
        _hostURL = nil;
        [self release];
    }

    // return either self or a pre-existing unique instance
    return ( result );
}

- (void) dealloc
{
    // non-GC objects need to explicitly remove themselves from the uniqueing table
    [[self class] removeUniqueHost: self];
    [_hostURL release];
    [super dealloc];
}

// no need for -finalize -- under GC we use NSHashTable with weak references

- (NSUInteger) hash
{
    return ( [_hostURL hash] );
}

- (BOOL) isEqual: (MyHost *) other
{
    if ( other == self )
        return ( YES );

    return ( [_hostURL isEqual: other->_hostURL] );
}

+ (MyHost *) uniqueHost: (MyHost *) aHost
{
    if ( __uniqueObjects == nil )
    {
        // use low-level routine to check, because iPhone has no NSGarbageCollector class
        // we use NSHashTable or NSMutableSet, because they both respond to the same messages (NSHashTable is modeled on NSMutableSet)
        if ( objc_collectingEnabled() )
        {
            // hash table has zeroing weak memory, object equality (uses -isEqual:), and does NOT copy objects, just retains them
            __uniqueObjects = [[NSHashTable hashTableWithWeakObjects] retain];
        }
        else
        {
            CFSetCallBacks cb = {
                0,                  // version
                NULL,               // retain (non-retaining references)
                NULL,               // release (non-retaining references)
                CFCopyDescription,  // CF (plain C function) equivalent for -description
                CFEqual,            // CF (plain C function) equivalent for -isEqual:
                CFHash              // CF (plain C function) equivalent for -hash
            }
            __uniqueObjects = (NSMutableSet *) CFSetCreateMutable( kCFAllocatorDefault, 0, &cb );
        }
    }

    MyHost * result = nil;
    @synchronized(__uniqueObjects)
    {
        // treat both like an NSMutableSet & we're golden
        // we use the -member: function to get an existing matching object from the collection
        result = [[__uniqueObjects member: aHost] retain];
        if ( result == nil )
        {
            // store & return the passed-in host object
            [__uniqueObjects addObject: aHost];
            result = aHost;
        }
    }

    return ( result );
}

+ (void) removeUniqueHost: (MyHost *) aHost
{
    if ( __uniqueObjects == nil )
        return;     // shouldn't ever happen, but it's a good idea to check at least

    @synchronized(__uniqueObjects)
    {
        [__uniqueObjects removeObject: aHost];
    }
}

@end

Надеюсь, я положил здесь достаточно, чтобы ответить на любые вопросы / мысли, которые могут у вас возникнуть об этом шаблоне проектирования.

1 голос
/ 11 мая 2009

Я думаю, лучшее решение здесь - это Multiton (это как Map с отображением 1 к 1, http://en.wikipedia.org/wiki/Multiton_pattern).

У него будет 2 метода - getHost (String hostIdentifier) ​​и returnHost (String hostIdentifier).

Для каждого хоста у него должен быть счетчик. Если counter == 0 и вызывается метод getHost, вам следует создать новый экземпляр требуемого хоста и увеличить счетчик.

Если counter == 1 и returnHost вызывается, вам следует удалить экземпляр хоста и уменьшить счетчик.

Вам также следует подумать о безопасности потоков.

1 голос
/ 11 мая 2009

Обычно я реализую этот тип шаблона с чем-то вроде + (id) hostWithIdentifier: (id) someIdentifier; метод (замените лучшие типы там, где он известен), который использует NSMapTable для отслеживания элементов со слабыми ссылками. Если экземпляр для данного идентификатора не найден, он выделяет его и помещает в таблицу.

Обратите внимание, что если вы не используете GC, вам нужно очистить запись в NSMapTable в методе -dealloc вашего хост-объекта.

Также обратите внимание, как кто-то еще сказал, что вы будете осторожны, если это многопоточный код. Используйте какой-нибудь механизм блокировки.

0 голосов
/ 11 мая 2009

Похоже, что каждый отдельный хост-объект представляет собой шаблон Singleton. Не могли бы вы просто сохранить коллекцию отдельных синглетонов?

0 голосов
/ 11 мая 2009

1. А как насчет простого 'пула объектов' ?

2. Смотрите там Я не объективный разработчик, хотя

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...