在软件开发中,面向对象的设计原则是指导如何构建软件架构的重要准则。其中,开闭原则(Open-Closed Principle,OCP)是其中一个核心原则,它指导设计出易于扩展且难以修改的系统。开闭原则的核心思想是:软件实体应当对扩展开放,对修改关闭。这意味着一个软件实体应当允许新的功能被添加,而不应当通过修改现有的代码来实现。
让考虑一个简单的银行模块,该模块负责根据不同的账户类型计算利息。假设银行为客户提供三种类型的账户:储蓄账户、基础支票账户和货币市场存款账户。每种账户类型都有不同的利率,利息的计算还考虑了诸如存款金额、每月平均余额等因素。基于这些业务规则,设计了一个名为Accounts的类,用于根据账户类型计算利息。
public enum AccountType
{
Savings,
Checking,
MoneyMarket
}
public class Accounts
{
private AccountType accountType { get; set; }
public Decimal CalculateInterest()
{
Decimal interest = 0;
if (accountType == AccountType.Savings)
{
// 考虑业务规则,计算储蓄账户的利息
interest = 2.50m;
}
else if (accountType == AccountType.Checking)
{
// 考虑业务规则,计算支票账户的利息
interest = 3.50m;
}
else
{
// 考虑业务规则,计算货币市场账户的利息
interest = 5.00m;
}
return interest;
}
}
上述解决方案对于客户银行来说非常完美,应用程序上线后,每个人都很高兴。几个月后,银行意识到其他银行通过发行定期存款账户赚取了利润,因此也应该这样做,所以让改变系统以适应这一点。现在修订后的系统看起来像这样:
public enum AccountType
{
Savings,
Checking,
MoneyMarket,
CertificatesOfDeposit
}
public class Accounts
{
private AccountType accountType { get; set; }
public Decimal CalculateInterest()
{
Decimal interest = 0;
if (accountType == AccountType.Savings)
{
// 考虑业务规则,计算储蓄账户的利息
interest = 2.50m;
}
else if (accountType == AccountType.Checking)
{
// 考虑业务规则,计算支票账户的利息
interest = 3.50m;
}
else if (accountType == AccountType.CertificatesOfDeposit)
{
// 考虑业务规则,计算定期存款账户的利息
interest = 6.35m;
}
else
{
// 考虑业务规则,计算货币市场账户的利息
interest = 5.00m;
}
return interest;
}
}
从上述场景中不难猜测,每次银行想要推出另一种账户类型或更改现有账户类型的业务规则时,都会经历相同的过程。这就是违反了开闭原则的地方。
为了解决这个问题,可以创建一个公共接口,所有代表账户类型的类都将实现这个接口。这样做的好处是未来的更改可以更好地适应,而不需要修改相应的类。
public interface IAccount
{
Decimal CalculateInterest();
}
public class SavingsAccounts : IAccount
{
public decimal CalculateInterest()
{
return 2.50m;
}
}
public class CheckingAccounts : IAccount
{
public decimal CalculateInterest()
{
return 3.50m;
}
}
public class MoneyMarketAccounts : IAccount
{
public decimal CalculateInterest()
{
return 5.00m;
}
}