美文网首页架构设计
iOS 开发中的渐进式设计:先简单实现,再优雅扩展

iOS 开发中的渐进式设计:先简单实现,再优雅扩展

作者: 黄花菜先生 | 来源:发表于2025-08-26 16:10 被阅读0次

架构师的价值不在于构建永恒完美的系统,而在于让系统能以最小成本持续演进。

一、在「写死」与「过度设计」之间求平衡

iOS 项目开发里,我们常常走向两个极端:

1. 过度设计 (Over-engineering)

  • 表现:一上来就写一堆 @protocol、抽象基类,预测未来可能的各种需求。
  • 问题:违背 YAGNI (You Aren’t Gonna Need It),耗时耗力,复杂度反而更高。
  • OC 常见场景:协议只有一个实现,继承层次不必要地过深。

2. 毫无设计 (No design)

  • 表现:所有逻辑都堆在 UIViewController 里,方法动辄几百行。
  • 问题:需求一变,改动一处牵一发而动全身,重构风险极高。

真正的挑战:如何找到一个中间点,既能快速交付,又能低成本应对变化?

二、渐进式重构:像搭乐高一样写代码

渐进式设计的核心:
先用简单可用的“积木”完成需求,等真正遇到变化时,再替换或增强积木,而不是一开始就造复杂的系统。

阶段一:简单实现,清晰隔离

初始版本只做当前需求,同时通过 Delegate/Block 预留扩展点。

// ShakeView.h
@interface ShakeView : UIView
@property (nonatomic, copy) void (^onAnimationStart)(void);
- (void)startShakeAnimation;
@end

// ShakeView.m
@implementation ShakeView

- (void)startShakeAnimation {
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position.x"];
    animation.duration = 0.3;
    animation.autoreverses = YES;
    animation.fromValue = @(self.center.x - 10);
    animation.toValue = @(self.center.x + 10);
    [self.layer addAnimation:animation forKey:@"shake"];
    
    if (self.onAnimationStart) {
        self.onAnimationStart();
    }
}
@end

要点

  • 快速完成核心逻辑(动画)。
  • 通过 Block/Delegate 低成本预留扩展(声音、埋点等)。
  • 保持方法单一,命名清晰,方便后续拆分。

阶段二:需求驱动,抽离协议

当出现以下情况时,就该考虑抽象:

  1. 同一功能出现第二、第三种实现。
  2. 产品 roadmap 明确未来会有多种策略。
  3. 测试发现 if-else 分支过多,难以覆盖。

重构为策略模式:

// 协议定义
@protocol ShakeViewAnimator <NSObject>
- (void)addAnimationToView:(UIView *)view;
@end

// 默认动画器
@interface BasicShakeAnimator : NSObject <ShakeViewAnimator>
@end
@implementation BasicShakeAnimator
- (void)addAnimationToView:(UIView *)view {
    // 简单晃动
}
@end

// 高级动画器
@interface PremiumBounceAnimator : NSObject <ShakeViewAnimator>
@end
@implementation PremiumBounceAnimator
- (void)addAnimationToView:(UIView *)view {
    // 更复杂的弹跳
}
@end

// ShakeView 支持注入策略
@interface ShakeView : UIView
@property (nonatomic, strong) id<ShakeViewAnimator> animator;
- (void)startShakeAnimation;
@end

@implementation ShakeView
- (void)startShakeAnimation {
    [self.animator addAnimationToView:self];
    if (self.onAnimationStart) {
        self.onAnimationStart();
    }
}
@end

使用方式:

ShakeView *shakeView = [[ShakeView alloc] initWithFrame:frame];
shakeView.animator = [PremiumBounceAnimator new];
[shakeView startShakeAnimation];

好处

  • 避免继承膨胀 (BasicShakeView, PremiumShakeView …)。
  • 新增动画方式只需实现一个 Animator,不动 ShakeView 本身。
  • 遵循 OCP(开放封闭原则),演进成本低。

阶段三:SOLID 原则的自然涌现

在代码渐进到这一阶段时,你会发现:

  • SRP:ShakeView 只负责协调,动画交给 Animator。
  • OCP:新增功能时无需修改 ShakeView。
  • DIP:ShakeView 依赖抽象协议,而非具体类。
  • LSP:任何 Animator 都能替换使用。
  • ISP:协议单一、专注。

原则不是硬套,而是代码演进的自然结果。

三、总结与实践建议

  1. 始于简单:相信 YAGNI,首版代码够用即可。
  2. 预见变化:只提前抽象最可能且代价最高的点。
  3. 三次法则:变化出现第三次,就该抽象。
  4. 发挥 OC 动态性:用 Category、消息转发等做低侵入式扩展。

最终目标是:
当下足够简单,未来足够灵活;当前成本最低,演进成本可控。

相关文章

网友评论

    本文标题:iOS 开发中的渐进式设计:先简单实现,再优雅扩展

    本文链接:https://www.haomeiwen.com/subject/xdbrajtx.html