[英]Using the State design pattern in Objective-C
我是 Objective-C 的新手,我正在学习 OOP 设计模式,但我是一位经验丰富的函数式程序员。 我相信我需要使用 State 设计模式来实现我的按钮,但我不确定最好的方法是什么。
目前,按钮具有三种状态: ACTIVE
、 INACTIVE
和FINISHED
。 根据按钮所处的状态,它将以不同的方式绘制。 我的计划不是为每个状态使用switch
或子类化按钮,而是使用三个不同的类别,每个类别都覆盖MyButton
的drawRect:
方法。 然而,环顾四周后,我发现这是非常不鼓励的。
解决这个问题的最佳方法是什么? 我应该对按钮进行子类化,使用类别还是委托,还是有其他我没有想到的解决方案?
编辑:我应该补充一点,虽然我不是在构建游戏,但我的状态模式基于这里的解释。
答案取决于您如何尝试更改按钮的外观。 如果您可以通过设置按钮的图像或其他标准属性来获得所需的内容,那么我将单独保留按钮类,而只需从外部视图模型类中对其进行配置。 让按钮负责管理UIControlState并从您的视图控制器或单独的视图模型类配置它。
如果您需要彻底改变按钮的外观,那么子类化并提供您自己的 drawRect: 是正确的方法,尽管即使在那里我也会考虑定义该类以具有处理您不同的渲染需求并保持状态所需的最少代码机外按钮。 从概念上讲,按钮应该负责绘制自身并检测用户事件,更复杂的应用程序逻辑应该由委托类处理。 保持您的 UI 组件简单且可重用。
将委托(通过协议)视为第一选择。 因为委托为您提供了一种松散耦合、灵活的方式来自定义行为。 (delegate = 观察者模式) 无论如何,这通常感觉太冗长了。
仅在必须时才考虑子类化和覆盖。 子类化/覆盖是一个强大的构造,它像其他过于强大的构造一样非常脆弱。 因为您需要正确处理超类方法的调用,以免破坏该功能。 那么它应该非常小心地使用。 (最近的编译器可能会在某些情况下发出警告)不幸的是,许多 Cocoa 功能都基于子类化,然后子类化通常成为唯一的选择。 在这种情况下,您使用的是UIView
类,而UIView
类不支持通过委托自定义绘制行为,那么您必须使用具有适当状态值的子类化。
永远不要考虑用类别来覆盖方法。 该功能不是为了覆盖,实际上对现有方法的隐式和静默覆盖是类别的问题之一。 (现在在某些情况下编译器会警告您)
您有另一种称为Objective-C 块的方式,而不是委托模式,后者是一个 Objective-C 版本的闭包。 在许多情况下,块可以代替委托和目标-动作模式,但有时不鼓励,因为它的隐式捕获行为可能会导致内存管理问题。
虽然drawRect:
足以提供按钮的自定义外观,但绘制是非常昂贵的操作,您需要尽可能避免它。 如果您的按钮具有静态外观,那么最好使用位图图像。 UIButton
已经有方法来支持这一点。
不仅对于UIButton
,许多 UIKit 类都提供了内置的外观自定义功能,我建议您主要考虑使用内置功能。
然后,如何为特定状态运行代码? UIButton
已经有一个功能。 它的超类UIControl
有一个名为addTarget:action:forControlEvents:
的内置方法,您可以使用它来注册一个观察者方法。 这类似于委托模式,然后它更健壮。 此外,这是处理按钮行为的设计和预期方式。 Cocoa 中的很多东西都是这样预定义的,你可能需要花一些时间来寻找现有的设计意图。
这些功能被嵌入到按钮类中,不如通过实现自己的状态模式/机器来提供自己的绘图实现灵活。 但强烈推荐,因为这是提供典型系统默认 iOS 应用行为的语义/实际精确行为的唯一方法。
如果你想覆盖 drawRect: 在按钮状态下,那么子类将是最好的选择。
您应该继承 UIButton 并创建一个新方法来处理它。 例如,您可能会调用您的子类 MYButton 并放置一个名为的新方法:
-(void) setButtonState: (NSInteger) 状态;
在其中,您可能想要执行以下操作:
-(void) setButtonState: (NSInteger) state {
开关(状态){
案例活跃:
//如果要更改图像等,请执行 ACTIVE CHANGES 等操作,例如 [self setImage: forState:]。
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.