我正在寻找一种设计模式来管理一个对象池。线程可以请求一个对象,在我的例子中是一个表示远程主机的对象。
如果主机对象不存在,则创建它,添加到池中并返回引用。
如果另一个线程或对象请求相同的(远程主机)对象,它也会被赋予引用。如果请求了不同的远程主机,则会创建它并将其添加到对象的“池”中。
任何线程或对象不再需要主机对象后,将其从池中自行删除。
答案 0 :(得分:5)
使用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 :(得分:1)
我认为,这里最好的解决方案是Multiton(就像Map 1到1的映射,http://en.wikipedia.org/wiki/Multiton_pattern)。
它将有2个方法 - getHost(String hostIdentifier)和returnHost(String hostIdentifier)。
对于每个主机,它应该有一个计数器。如果counter == 0并调用方法getHost,那么你应该创建所需主机的新实例并增加计数器。
如果counter == 1并且调用了returnHost,则应删除主机实例并减少计数器。
您还应该考虑线程安全性。
答案 2 :(得分:1)
我通常会用类似的东西来实现这种模式 +(id)hostWithIdentifier:(id)someIdentifier; 方法(替换已知的更好类型),它使用NSMapTable来跟踪具有弱引用的项目。如果找不到给定标识符的实例,则会分配该实例并将其放入表中。
请注意,如果您不使用GC,则需要在主机对象的-dealloc方法中清除NSMapTable中的条目。
另请注意,正如其他人所说,如果这是多线程代码,您会要小心。使用某种锁定机制。
答案 3 :(得分:0)
1.简单'Object Pool'怎么样?
2. See there我不是客观的开发者,但是
答案 4 :(得分:0)
听起来每个主机对象都是Singleton模式。你能保留一些单身人士的集合吗?