我一直想知道在什么情况下在objective-C中采用单例模式是非常必要的(例如,定义一个专用类并创建一个单独的实例),使用类作为对象是不行的。
特别是,我正在考虑以下解决方案:
static
变量(文件范围全局变量),而不是单例实例的实例变量; 例如,您可以将所有纹理创建/清理实现为Texture
类(模型对象)和 TextureManager
单例(资源管理器),而不是类方法和相同Texture
类的静态变量(工厂模式加上一些资源管理)。
对此设计的任何想法?
修改
现在我想到了它,并且仍然在上面的Texture
示例中,即使我将两个类分开(Texture
和TextureManager
),我必须在A之间做出选择。让经理成为单例,并使用实例方法操作它,或B.使管理器成为无实体的辅助类。澄清:
Texture* myTexture = [[TextureManager defaultManager] textureWithName:@"TextureName"];
// (singleton, client uses instance methods)
与
Texture* myTexture = [TextureManager textureWithName:@"TextureName"];
// (Class standing in for singleton, client uses class methods)
后者看起来更简单,不那么繁琐/冗长,但我想知道哪种设计“更正确”。当然,前者允许出现不止一个TextureManager
实例(不是在我的情况下)。
答案 0 :(得分:7)
我一直在考虑同样的事情,我想我有一个答案。
这取决于你需要做什么。两者都不一定更“正确”。
如果您想详细了解我的结论或向下滚动到 tl; dr 部分,请继续阅读。
正如你所说,访问单例以让类为你管理单例会显得(外部)不那么麻烦。基本上你可以通过用初始化方法替换singleton的工厂方法来实现。查看Apple's documentation,您可以看到它们显示“共享”方法的位置,该方法充当工厂,根据需要生成单例。
static MyGizmoClass *sharedGizmoManager = nil;
+ (MyGizmoClass*)sharedManager
{
if (sharedGizmoManager == nil) {
sharedGizmoManager = [[super allocWithZone:NULL] init];
}
return sharedGizmoManager;
}
您可以使用void初始值设定项替换方法,而不是这样:
+ (void)initializeMyGizmo
{
if (sharedGizmoManager == nil) {
sharedGizmoManager = [[super allocWithZone:NULL] init];
}
// whatever else needs to be done to the singleton to initialize it
}
然后仅使用类方法,并允许MyGizmoClass
管理单身内容的更新,例如[MyGizmoClass setGizmoName:@"Gadget"]
。
注意:在此方案中,对于查看.h
文件以查看属性的人来说会很困惑,在这种情况下,他们可能会得出结论他们应该自己创建一个对象的实例,或者能够以某种形式或方式访问单例。所以如果你想要封装对单例的访问权限,那么使用公共变量是不明智的。
到那时:
如果您仅通过课程本身限制访问权限,则会丢失任何与属性一起出现的getter和setter或其他免费内容。这意味着,如果MyGizmoClass
作为其模型的一部分NSString *gizmoName
,您将被迫为此“属性”创建自定义getter和setter,并将其保存为接口中的ivar或property单例类的.m
文件(即私有)中的扩展,或者作为相邻的静态变量。
所以这引出了一个问题(并且首先让我思考的是),我们是否应该包含行static MyGizmoClass *sharedGizmoManager = nil;
或者我们是否可以完全修改内部接口扩展并替换任何可能的ivars或属性我们想要在实现中限制对static
实现的访问?
我已经回答了......
这取决于您需要做什么。
如果你(甚至一点点机会)需要继承你的
TextureManager
或者可以创建它的多个实例(制作它
不再是单身人士)坚持常规会更好
单身的Apple惯例。
这包括多个“单身人士”,其中你可能有几个
TextureManager
已预先配置了不同的设置。
在这种情况下,您可以根据需要使用属性(公开或
私人)以及伊娃。你也可以混合使用ivars和
静态,但你仍然需要有一个静态实例
TextureManager
实施中的TextureManager
。
如果您仅将需要一个 TextureManager
的实例,它将完全独立运行而不会进一步向下混合然后,您可以在.m
文件的实现中完全删除类的静态实例,并将ivars和properties替换为该实现中的静态变量。
如果要在CoreData中存储属性或设置,并且只需要它们进行配置,这将非常有用。
请记住在这种情况下,您必须为静态变量创建所有getter和setter,并且只能使用类方法访问它们(但这很重要)。
This answer为何时以及如何调用“初始化程序”方法或创建单例提供了一个有趣的解决方案。这可以与每个场景一起使用,以初始化第一个场景中的单例,或者将默认值预加载到第二个场景中的类级静态。
如果您想在实现中坚持使用静态单例,您可以查看this article,以便更好地了解单例的真正“全局范围”。
答案 1 :(得分:2)
是的,你绝对可以制作一个Texture类而不需要单例。
单身人士可能不应该被创造并用作对象。
单身人士可以用于许多重要的事情
我当然不知道他们可以用的所有东西,但我会告诉你我过去用过的东西。
我通常在多级游戏(如愤怒的小鸟)中使用单身人士进行关卡导航 通过关卡导航,我的意思是......当一个玩家在游戏中完成某个关卡时,我只需在单例上调用一个类方法并传入关卡编号,然后单例的类方法计算下一个关卡(如果用户按下) '下一级'按钮)。
答案 2 :(得分:2)
我可以帮助您更好地理解Singleton类,并在适用时。
模式:Singleton
意图:强制某个类只能拥有一个实例,并使该实例可以被任何其他对象访问。
动机:有时我们需要确保在我们的问题域中只存在某种类型的单个对象。示例:学生只携带一个背包,可以装满书籍。我们不想把他和二手背包联系在一起,甚至还有更多的书。
何时使用: