概述
软件实体,比如说类,模块,功能等,应当为扩展开放,但是对修改关闭,什么意思呢?就是说,在一个现有的工程完毕之后,以后所有的新添加的功能应当在不修改原有代码的基础上进行,不应当在已有的代码上进行任何的代码修改或者逻辑的修改添加操作。
简介
下面以一个银行存取的程序来讲解,既然是银行存储,那么就少不了存款,取款和利息计算等方面。
namespace OpenCloseDaemon { public enum AccountType { SAVINGS, FIXEDDEPOSIT, SALAEY } public class Account { private AccountInfo accInfo; private AccountType type; private double balance; public Account(double balance,AccountType type) { this.balance = balance; this.type = type; } public void Withdraw(double amount) { balance -= amount; } public void Deposit(double amount) { balance += amount; } public void CalculateInterest() { switch (type) { case AccountType.SALAEY: //implementation break; case AccountType.FIXEDDEPOSIT: //implementation break; case AccountType.SAVINGS: //implementation break; default: break; } } } }
在后续的扩展中,也许会有其他的功能模块需要被添加到Account类中。如果银行需要添加更多的类型,那么这个Account类将会被修改,这种修改将会带来不可预知的Bug或者是其他类型的错误。同时,这种修改也许会造成枚举类型的改变。与此同时,依赖Account类的所有其他的模块都将受到影响,看来,重新的编译,测试,部署将是不得不采取的办法。项目小的话,尚可接受,但是一旦项目巨大,那么带来的时间损失将是无法弥补的。所以,这里我们需要重构。
重构
开放封闭原则的引入,将会很大程度上改善这种境况,对于开放封闭原则来说,代码应该按照如下的方式进行重构:
l 模块应该对扩展开放。也就是说,我们只做添加新代码的行为。
l 已有的代码对修改关闭。也就是说,你不需要或者极少需要修改已经存在的代码。
面向对象通过类的抽象和多态,为我们提供了更好的去利用开放封闭原则的方法。当我们把这些应用到Account类中的时候,我们就可以得到一个分工明确的组织结构。
Account.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace OpenCloseDaemons { abstract class Account { private AccountInfo accInfo; protected double balance; public Account(double balance) { this.balance = balance; } public void Withdraw(double amount) { balance -= amount; } public void Deposit(double amount) { balance += amount; } public abstract void CalculateInterest(); } }
AccountInfo.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace OpenCloseDaemons { class AccountInfo { string name; string address; string account_no; string basebranch; } }
FixedDeposit.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace OpenCloseDaemons { class FixedDeposit:Account { public FixedDeposit(double balance):base(balance) { } public override void CalculateInterest() { //Implementation here } } }
Savings.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace OpenCloseDaemons { class Savings:Account { public Savings(double balance):base(balance) { } public override void CalculateInterest() { //Implementation } } }
通过重构,我们可以看到,现成的模块,不论是原本的还是新添加的,都需要依赖于抽象类Account,如果其中的任何模块发生改变都不会对已有的类产生任何影响。另外一个好处是通用的代码都被提取出来,避免了重复利用。