SOLID编程原则的实践与应用

在软件开发中,经常听到“让代码更健壮”的建议。那么,究竟什么是健壮的代码呢?SOLID原则是五个面向对象设计原则的集合,旨在提高代码的可维护性、可扩展性和灵活性。本文将探讨SOLID原则中的两个关键原则:依赖倒置原则和单一职责/开闭原则,并展示它们在实际编程中的应用。

依赖倒置原则

依赖倒置原则的核心思想是,高层模块不应该依赖于低层模块,两者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。这个原则对于单元测试尤为重要,因为它允许模拟和控制底层模块的行为。

考虑以下代码示例:

public class DateBasedTaxFactory : ITaxFactory { Customer _customer; ITaxFactory _taxFactory; public DateBasedTaxFactory(Customer c, ITaxFactory cb) { _customer = c; _taxFactory = cb; } public ITax GetTaxObject() { if (_customer.StateCode == "TX" && DateTime.Now.Month == 4 && DateTime.Now.Day == 4) { return new NoTax(); } else { return _taxFactory.GetTaxObject(); } } }

在这个例子中,DateBasedTaxFactory类直接依赖于DateTime.Now属性来确定日期。这使得在不改变系统时间的情况下进行单元测试变得困难。为了解决这个问题,可以引入依赖注入,让外部决定类的依赖项。

public class DateBasedTaxFactory : ITaxFactory { Customer _customer; ITaxFactory _taxFactory; DateTime _dt; public DateBasedTaxFactory(Customer c, ITaxFactory cb, DateTime dt) { _customer = c; _taxFactory = cb; _dt = dt; } public ITax GetTaxObject() { if (_customer.StateCode == "TX" && _dt.Month == 4 && _dt.Day == 4) { return new NoTax(); } else { return _taxFactory.GetTaxObject(); } } }

通过这种方式,可以在测试中传递任意日期,从而验证DateBasedTaxFactory类的行为。

单一职责/开闭原则

单一职责原则指出,一个类应该只有一个引起它变化的原因。开闭原则则表明,软件实体应当对扩展开放,对修改封闭。这意味着应该设计出易于扩展但不需要修改现有代码的系统。

考虑以下订单计算总金额的代码:

public class Order { List _orderItems = new List(); public decimal CalculateTotal(Customer customer) { decimal total = _orderItems.Sum(item => item.Cost * item.Quantity); decimal tax; if (customer.StateCode == "TX") { tax = total * .08m; } else if (customer.StateCode == "FL") { tax = total * .09m; } else { tax = .03m; } total = total + tax; return total; } }

如果税率逻辑发生变化,或者需要添加新的州税率,就需要修改Order类。这可能会导致需要重新测试和发布整个BusinessLogic.dll,这在实际操作中是非常不方便的。为了解决这个问题,可以将税率逻辑抽象到单独的类中。

public interface ITax { decimal CalculateTax(decimal total); } public class TXTax : ITax { public decimal CalculateTax(decimal total) { return total * .08m; } } public class CustomerBasedTaxFactory : ITaxFactory { Customer _customer; static Dictionary stateTaxObjects = new Dictionary(); static Dictionary countyTaxObjects = new Dictionary(); public CustomerBasedTaxFactory(Customer customer) { _customer = customer; } public ITax GetTaxObject() { ITax tax; if (!string.IsNullOrEmpty(_customer.County)) { if (!countyTaxObjects.Keys.Contains(_customer.StateCode)) { tax = (ITax)Activator.CreateInstance("Tax", "solid.taxes." + _customer.County + "CountyTax"); countyTaxObjects.Add(_customer.StateCode, tax); } else { tax = countyTaxObjects[_customer.StateCode]; } } else { if (!stateTaxObjects.Keys.Contains(_customer.StateCode)) { tax = (ITax)Activator.CreateInstance("Tax", "solid.taxes." + _customer.StateCode + "Tax"); stateTaxObjects.Add(_customer.StateCode, tax); } else { tax = stateTaxObjects[_customer.StateCode]; } } return tax; } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485