赣州微网站建设费用,开封市建设中专网站,青海做网站的公司,房地产客户管理系统2.2 Composition over Inheritance#xff1a;组合优于继承的实际应用
继承#xff08;Inheritance#xff09;是面向对象编程中最容易被过度使用和误用的特性之一。传统的教学往往让人们优先选择继承来实现代码复用和建立“是一个#xff08;is-a#xff09;”的关系。然…
2.2 Composition over Inheritance组合优于继承的实际应用
继承Inheritance是面向对象编程中最容易被过度使用和误用的特性之一。传统的教学往往让人们优先选择继承来实现代码复用和建立“是一个is-a”的关系。然而在复杂的业务系统中严格的继承层次结构常常会变得僵化、脆弱最终难以维护。
“组合优于继承”Composition over Inheritance是一条经典的设计原则它倡导通过将对象组合在一起而不是通过继承来扩展功能。它旨在构建“有一个has-a”或“使用一个uses-a”的关系从而获得更大的灵活性。
2.2.1 继承的陷阱脆弱的基类问题
让我们看一个典型的滥用继承的例子
// 一个看似合理的继承层次结构
public abstract class OrderProcessorBase {public virtual void Validate(Order order) {// 基础验证逻辑}public virtual decimal CalculateTotal(Order order) {// 计算总价的基础逻辑return order.Items.Sum(i i.Price * i.Quantity);}public void Process(Order order) {Validate(order);order.Total CalculateTotal(order);// ... 其他处理步骤如保存、通知等}
}// 为特定场景扩展
public class OnlineOrderProcessor : OrderProcessorBase {public override void Validate(Order order) {base.Validate(order); // 先执行基础验证// 添加在线订单特有的验证如配送地址必填if (string.IsNullOrEmpty(order.ShippingAddress))throw new InvalidOperationException(Shipping address is required.);}public override decimal CalculateTotal(Order order) {decimal baseTotal base.CalculateTotal(order);// 添加在线订单特有的费用如运费return baseTotal 5.0m;}
}public class TaxFreeOrderProcessor : OrderProcessorBase {public override decimal CalculateTotal(Order order) {// 免税订单需要完全重写计算逻辑可能无法有效复用基类逻辑return order.Items.Sum(i i.PriceBeforeTax * i.Quantity);}
}这个设计的问题在于
脆弱的基类Fragile Base Class对 OrderProcessorBase 的任何修改例如添加一个新的虚拟方法修改 Process 方法的流程都可能会无声地破坏所有子类的行为。子类与基类紧密耦合基类变得“脆弱”。爆炸性的子类如果现在需要处理一种“在线且免税”的订单你该怎么办创建 OnlineTaxFreeOrderProcessor这会导致类层次结构爆炸产生复杂的菱形继承问题C#不支持多继承此路不通。不灵活的复用TaxFreeOrderProcessor 无法复用基类 CalculateTotal 的逻辑只能重写可能导致代码重复。单一演化方向继承强制子类沿着基类的单一维度进行演化。但现实世界的需求变化往往是多维度的如支付方式、客户等级、订单来源等。
2.2.2 组合的解决方案策略模式与行为注入
让我们用“组合”来重新设计上面的例子。我们将不同的行为验证、计算抽取出来定义为独立的策略接口。
// 1. 定义抽象策略接口
public interface IOrderValidationStrategy {void Validate(Order order);
}
public interface IOrderCalculationStrategy {decimal CalculateTotal(Order order);
}
// ... 可以定义更多策略接口如 INotificationStrategy, IPersistenceStrategy// 2. 实现各种具体策略
public class StandardValidationStrategy : IOrderValidationStrategy {public void Validate(Order order) { /* 基础验证逻辑 */ }
}
public class OnlineOrderValidationStrategy : IOrderValidationStrategy {public void Validate(Order order) {// 包含基础验证和在线特有验证new StandardValidationStrategy().Validate(order);if (string.IsNullOrEmpty(order.ShippingAddress))throw new InvalidOperationException(Shipping address is required.);}
}
//---
public class StandardCalculationStrategy : IOrderCalculationStrategy {public decimal CalculateTotal(Order order) order.Items.Sum(i i.Price * i.Quantity);
}
public class OnlineCalculationStrategy : IOrderCalculationStrategy {public decimal CalculateTotal(Order order) new StandardCalculationStrategy().CalculateTotal(order) 5.0m;
}
public class TaxFreeCalculationStrategy : IOrderCalculationStrategy {public decimal CalculateTotal(Order order) order.Items.Sum(i i.PriceBeforeTax * i.Quantity);
}// 3. 核心订单处理器通过组合各种策略来完成工作
public class OrderProcessor {private readonly IOrderValidationStrategy _validationStrategy;private readonly IOrderCalculationStrategy _calculationStrategy;// ... 其他策略// 策略通过构造函数注入。这提供了极大的灵活性public OrderProcessor(IOrderValidationStrategy validationStrategy,IOrderCalculationStrategy calculationStrategy){_validationStrategy validationStrategy;_calculationStrategy calculationStrategy;}public void Process(Order order) {_validationStrategy.Validate(order);order.Total _calculationStrategy.CalculateTotal(order);// ... 使用其他策略}
}现在如何创建那个令人头疼的“在线且免税”订单处理器变得非常简单
// 在应用程序的 composition root (通常是DI容器配置处) 进行组装
var processorForComplexOrder new OrderProcessor(validationStrategy: new OnlineOrderValidationStrategy(), // 使用在线验证calculationStrategy: new TaxFreeCalculationStrategy() // 使用免税计算
);// 或者你可以创建新的组合策略而不是新的Processor类
public class OnlineTaxFreeCalculationStrategy : IOrderCalculationStrategy {public decimal CalculateTotal(Order order) {decimal baseTotal new StandardCalculationStrategy().CalculateTotal(order);return baseTotal 5.0m; // 在线费用但免税逻辑已融入这里设计需要斟酌}
}
// 更好的方式是认识到“加运费”和“免税”是两个正交的关切点可能需要更细粒度的策略组合。2.2.3 组合的优势与架构师视角
灵活性Flexibility你可以动态地组合任何验证策略和任何计算策略轻松应对“在线且免税”这种多维度的需求变化而无需修改现有类或创建复杂的继承树。解耦DecouplingOrderProcessor 不再与任何具体的业务实现耦合它只依赖于接口。各个策略之间也是相互独立的。可测试性Testability可以轻松地为 OrderProcessor 编写单元测试只需注入Mock的策略对象即可。单一职责Single Responsibility每个策略类都只有一个非常明确的职责符合SRP。开闭原则Open/Closed添加新的验证或计算方式新的策略实现完全不需要修改 OrderProcessor 或其他策略符合OCP。
何时使用继承
“组合优于继承”并非要完全否定继承。继承在以下场景仍然有效
建立严格的类型层次结构当存在真正的“is-a”关系且子类确实是基类的一个更具体的类型时如 Cat : Animal, Button : Control。需要多态当你需要让不同的子类对象对同一消息做出不同响应时。框架设计用于定义模板方法模式其中基类控制主要流程子类只负责实现特定的步骤。
决策指南
默认优先选择组合尤其是对于行为的扩展。询问自己“我是为了复用代码还是为了建立类型关系”如果主要是为了复用组合通常是更安全、更灵活的选择。如果使用继承确保子类和基类的关系是稳定且永久的避免设计深度过大的继承层次。利用依赖注入框架来管理这些可组合的策略对象这将使你的系统像由乐高积木组成一样可以轻松地拆卸和重组。
总结
从“继承思维”转变为“组合思维”是迈向高级软件设计的关键一步。它要求你从对象间的关系和行为的角度来思考而不是仅从分类的角度。通过将系统分解为一系列精细、单一职责、可插拔的组件并通过组合它们来构建复杂行为你将创建一个真正灵活、健壮且易于演进的架构。这种思维方式是理解后续依赖注入DI和更高级架构模式的基础。