无Nib的UIView子类是否违反里氏替换原则及SOLID?
这个NiblessView是否违反SOLID原则?尤其是里氏替换原则?
结论:确实违反了里氏替换原则(LSP),但属于iOS开发中常见的架构权衡选择
里氏替换原则的核心是:子类必须能够替换父类,且不会破坏原有代码的正确性。UIView作为父类,其公开契约包含了通过nib/故事板加载的能力——也就是init?(coder:)初始化器的可用性。任何依赖UIView的代码,都有理由认为可以通过这个初始化器创建实例。
你的NiblessView实现中,将init?(coder:)标记为unavailable并在调用时抛出致命错误,直接打破了这个契约:如果有一段代码期望接收任意UIView子类(比如通用的视图加载工具类),当传入NiblessView时会直接崩溃,这完全不符合LSP的要求。
但这个设计并非完全不可取
在依赖注入优先的架构中,禁止nib加载是一种刻意的约束:它强制开发者通过初始化器显式注入依赖,避免nib中隐含的控件绑定、属性设置等隐式依赖,从而提升代码的可测试性和可维护性。这是在SOLID原则的严格性和实际架构目标之间的权衡。
优化建议(减少LSP违反程度)
- 不要直接标记
init?(coder:)为不可用,而是在方法内部输出警告日志并返回nil,或者在类的文档注释中明确标注「该类不支持nib/故事板加载」 - 提供清晰的类注释,明确告知开发者该类的使用场景(仅支持代码初始化)
- 若想更贴合SOLID原则,可以考虑将「无nib加载」设计为一个协议(比如
Nibless),让需要该特性的UIView子类遵循协议,而非直接继承一个限制型父类,这样更符合接口隔离原则(ISP)
你的代码示例
import UIKit open class NiblessView: UIView { // MARK: Public Methods public override init(frame: CGRect) { super.init(frame: frame) } @available(*, unavailable, message: "Loading this view from a nib is unsupported in favor of initializer dependency injection.") public required init?(coder: NSCoder) { fatalError("Loading this view from a nib is unsupported in favor of initializer dependency injection.") } }
内容的提问来源于stack exchange,提问作者Retro
相关产品推荐
相关产品推荐

