“学习OO好榜样”之Divergent Change(发散式变化)、Shotgun Surgery(霰弹式修改)

本文探讨软件开发中遇到的两大挑战:“发散式变化”(Divergent Change)与“霰弹式修改”(Shotgun Surgery)。前者指单一类受多种功能变更影响,后者指一个功能变更导致多个类需修改。文中通过实际案例说明重构的重要性,并提出解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Divergent Change(发散式变化)
指的是“某一个类受到多种变化的影响”,A/B/C/D……多种功能变化的时候它都需要修改。
病因大致是某个类负担了多项任务,太操心了。很可能需要再拆分几个类出来,把变化封装得更细。
以前我写代码的时候有一个例子,曾经有一段时间,P_Unit类处理所有BSC单元的逻辑,但各种单板的逻辑是不一样的,于是DTB改逻辑的时候要修改P_Unit、ABPM改的时候要修改P_UNit、甚至HDLC/UID等逻辑修改的时候P_Unit都要改。显然该类管得太多了。后来,我看了<重构>这本书,痛下决心做了重构。想起来03年,徐峰做配置CAF的时候建议我每个板子一个类,我完全不以为然。显然当初没有理解“封装变化”这四个字。
 
Shotgun Surgery(霰弹式修改)
指的是“一个变化引发多个类的修改”,完成某个需求的时候,A/B/C/D……多个类都需要修改。
病因大致是多个类之间的耦合太严重。很可能是类没有规划好,没有把变化封装得足够令人满意。
记得水手好像说过,去掉这个Bad Smell不好强求。也有些道理。而且举出Abstract Factory模式作为例证。
但我们要清楚的认识到我们努力的方向,Abstract Factory模式同样不完美,它没有满足Open-Close原则。我们可以在某些条件(包括技术条件)受限的时候写出不完美的代码,但一定要知道它是不完美的。
### 代码坏味道:发散表面化的概念解决方案 代码坏味道(Code Smell)是指代码中某些结构或模,虽然在语法上没有错误,但可能导致代码难以维护、扩展或理解。其中,“发散表面化”(Divergent Change)是一种典型的代码坏味道,指的是一个类需要因为不同原因而频繁修改[^1]。 #### 发散表面化的定义 发散表面化通常表现为一个类承担了过多的责任,导致每次需求变更时,都需要对该类进行多处修改。这种设计违背了单一职责原则(Single Responsibility Principle, SRP),即一个类应该只负责一项功能或职责[^1]。 #### 解决方法 为了解决发散表面化的问题,可以采用以下几种设计思想和模: 1. **分离职责** 将类的职责分解到多个更小的类中,每个类专注于完成单一的功能。例如,如果一个类既负责业务逻辑处理,又负责数据存储操作,则可以将数据存储部分提取到单独的类中。 2. **应用设计模** - 使用**策略模(Strategy Pattern)**来封装可变的行为。通过将不同的行为抽象为独立的类,可以减少对原有类的修改需求。 - 使用**观察者模(Observer Pattern)**来解耦事件触发和处理逻辑,避免在一个类中同时管理多种事件的响应逻辑。 3. **重构技术** - **提取类(Extract Class)**:将相关属性和方法从原类中提取到一个新的类中。 - **移动方法(Move Method)**:将方法从当前类移动到另一个更合适的类中。 - **内联类(Inline Class)**:当某个类的功能过于简单时,可以将其合并到其他类中。 4. **引入领域驱动设计(DDD)** 在复杂的业务场景下,可以使用领域驱动设计的思想,将业务逻辑划分为不同的领域模型和聚合根(Aggregate Root)。每个模型专注于解决特定领域的业务问题,从而避免职责过度集中。 5. **自动化测试保障** 在重构过程中,确保有足够的单元测试覆盖,以验证代码行为的一致性。这有助于降低因重构带来的潜在风险[^1]。 ```python # 示例:通过策略模解决发散表面化 class PaymentProcessor: def __init__(self, strategy): self.strategy = strategy def process_payment(self, amount): return self.strategy.execute(amount) class CreditCardPaymentStrategy: def execute(self, amount): print(f"Processing {amount} via Credit Card") class PayPalPaymentStrategy: def execute(self, amount): print(f"Processing {amount} via PayPal") # 使用不同的支付策略 processor = PaymentProcessor(CreditCardPaymentStrategy()) processor.process_payment(100) # 输出: Processing 100 via Credit Card processor = PaymentProcessor(PayPalPaymentStrategy()) processor.process_payment(200) # 输出: Processing 200 via PayPal ``` #### 总结 通过分离职责、应用设计模、使用重构技术以及引入领域驱动设计等方法,可以有效解决代码中的发散表面化问题。这些方法不仅能够提高代码的可维护性和扩展性,还能使代码更加清晰易懂[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值