我正在制作一个计算器应用程序来学习Objective-C,并且可能会提高我的OO设计技巧。为了尝试更多MVClike,我已经将实际的do-the-calculator-stuff代码与视图控制器分开了。对于每个动作,几乎所有视图控制器都会告诉“模型”执行针对该动作的操作。
事情是,这给了我一堆方法,基本上什么也没做,只是将动作转发给模型,如下所示:
- (IBAction)clearAll:(id)sender {
[self.model clearAll];
}
- (IBAction)clearDisplay:(id)sender {
[self.model clearDisplay];
}
- (IBAction)clearMemory:(id)sender {
[self.model clearMemory];
}
- (IBAction)storeMemory:(id)sender {
[self.model storeMemory];
}
- (IBAction)addMemory:(id)sender {
[self.model addMemory];
}
- (IBAction) subtractMemory:(id)sender {
[self.model subtractFromMemory];
}
- (IBAction)recallMemory:(id)sender {
[self.model recallMemory];
}
到目前为止,Objective-C似乎非常灵活,可以动态转发消息,这些方法足够相似,可以轻松实现自动化。他们真的必须在那里吗?或者是否有一种重复性较低的方法告诉控制器只是将某些消息传递给模型(理想情况下,剥离sender
arg)?
我一直在寻找一些选择器和NSInvocation
的东西,但似乎通过取消所有(IBAction)
标记来解决这个问题按钮动作。 (在这些情况下,如果视图不必知道或关心控制器只是转发到模型,我更喜欢。)
那么,是否有较少的重复和/或hacky方式?还是不值得麻烦? (或者,这首先是一个坏主意?还是试图让模型做得太多?或者......)
答案 0 :(得分:4)
您可以使用该语言的动态功能。
来自Objective-C运行时编程documentation
当对象无法响应消息,因为它没有与消息中的选择器匹配的方法时,运行时系统会通过发送
forwardInvocation
来通知对象。
因此,在您的情况下,您可以按如下方式实现前向调用方法
- (void)forwardInvocation:(NSInvocation *)anInvocation {
if ([self.model respondsToSelector:[anInvocation selector]])
[anInvocation invokeWithTarget:self.model];
else
[super forwardInvocation:anInvocation];
}
注意强>
您还必须统一您的方法签名。删除sender
参数或将其添加到模型的方法中,否则respondsToSelector
将返回NO
并且不会调用该方法。
在这种情况下,forwardInvocation
将充当调度程序,它将尝试将控制器未实现的每条消息发送到self.model
对象。如果这不响应选择器,它将调用super
,很可能导致无法识别的选择器异常。
我个人觉得它非常优雅,即使你更清楚自己在做什么,也绝对不要过度使用这些功能。
答案 1 :(得分:4)
你可以做Gabriele建议的事情,它肯定是动态ObjC的一个例子,但你可能最好避免它。正如加布里埃尔所说,你最好知道自己在做什么,绝对不要过度使用这样的功能。并且 经常表明这样的功能可能比它的价值更麻烦。
现实情况是,您的计算器应用程序是为了驱动模型 - 视图 - 控制器模式固有的分离而设计的。正如你所说,它是一个学习应用程序。
实际上,没有任何应用程序如此简单。如果有的话,你很少会有一个按钮区域,控制层会盲目地将所述功能转发给模型。
相反,在该控制层中将存在所有业务逻辑方式,可以执行从自动化各种操作到验证(可能通过查询模型)到更新UI状态以响应各种操作的所有操作。
可能这个代码将在项目的早期阶段出现,因此通用转发机制将很快被完全废弃。
同样,这种转发机制在调试方面变得充满了痛苦。你不再有一个具体的地方可以放弃一个断点,但现在必须添加条件。您也没有简单的方法来查找可能调用或实现特定方法的所有位置。同样,它使控制流程更加困难。
如果你发现自己有很多重复的样板代码,那么更多的迹象表明你的架构可能存在缺陷,而不是需要注入一个漂亮的动态机制来减少重复性。
同样,如果你要继续充实你的计算器应用程序,你的编码时间会花多少时间用于重复的方法而不是应用程序中的所有其他功能?可能,非常非常小,并且由于它们的简单性和调试方便,所以重复的方法不太可能会产生任何显着的维护成本,而是一种狡猾的动作(这非常酷,我鼓励你在其他情况下探索)几乎可以保证要求“嗯。我在想什么?!”片刻之后。