开放封闭原则(Open Close Principle)简称OCP原则。
定义
软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的
说明
对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
示例
同样根据百度百科的示例进行分析
背景
银行的柜台业务处理流程:通常由客户通过排号系统获取一个排号,然后排队去完成相关的银行业务,其中每个柜台窗口都可以处理所有银行业务;假设当前银行分点的柜台业务有:存款,取款,转账3个业务,那么银行柜台职工类的设计如下:
package OCP.Example;//银行职工public class BankStaff{ public void handProcess(Client client) { //先询问客户的业务目的 int clientType = client.getClientType(); //根据业务目的去处理业务 switch(clientType) { //存款业务 case 1: System.out.println("存款"); break; //取款业务 case 2: System.out.println("取款"); break; //转账业务 case 3: System.out.println("转账"); break; } }}
客户类如下:
package OCP.Example;public class Client { private int clientType = 0;//客户到银行的业务目的 //客户构造函数 初始化客户的业务目的 public Client(int clientType) { this.clientType = clientType; } //获取客户的类型,即到银行的业务目的 public int getClientType() { return clientType; }}
虚拟演示场景代码如下:
package OCP.Example;//银行业务演示的虚拟场景public class Demo { public static void main(String args[]) { //首先创建演示对象 BankStaff staff1 = new BankStaff();//银行柜台职员对象 Client client1 = new Client(1);//客户对象,他是来存款的 //执行业务 staff1.handProcess(client1); }}
上面的代码首先违背了单一职责原则,一个银行职员承担了3中业务职责,但是对于客户来讲他仅仅需要提出业务需求就可以了。此外,如果新增加一个业务,如:理财业务,那么针对以上代码我们就必须得修改职员类代码了。这也就违反了开放封闭原则,像上面这样简单的代码,修改代码无可厚非,完全可以在程序员的掌控之中,但是现实项目中就不一样了,上述的业务操作可能很复杂,如果进行修改很可能会在加入新业务的同时影响到老业务,因此修改建议如下:
首先定义银行职员的业务接口
package OCP.Example;public interface IBankStaffWork { public void handleProcess();//业务处理接口}
将银行职员的职责进行分工:
存款职员类:
package OCP.Example;public class DepositMoneyStaff implements IBankStaffWork { @Override public void handleProcess(Client client) { System.out.println("存款"); }}
取款职员类:
package OCP.Example;public class DrawMoneyStaff implements IBankStaffWork { @Override public void handleProcess(Client client) { System.out.println("取款"); }}
转账职员类:
package OCP.Example;public class TransferAccountsStaff implements IBankStaffWork { @Override public void handleProcess(Client client) { System.out.println("转账"); }}
客户类
package OCP.Example;public class Client { //客户自己选择银行业务 public void selectStaff(IBankStaffWork staff) { staff.handleProcess(this); }}
虚拟演示场景代码如下:
package OCP.Example;//银行业务演示的虚拟场景public class Demo { public static void main(String args[]) { //首先创建演示对象 IBankStaffWork despositMoneyStaff = new DepositMoneyStaff();//存款职员 IBankStaffWork drawMoneyStaff = new DrawMoneyStaff();//取款职员 //转账职员 IBankStaffWork transferAccountsStaff = new TransferAccountsStaff(); Client client1 = new Client(); //创建客户对象 //执行业务 client1.selectStaff(despositMoneyStaff);//客户存款 client1.selectStaff(drawMoneyStaff);//客户取款 client1.selectStaff(transferAccountsStaff);//客户转账 }}
以上修改方案,对银行职员进行了单一职责处理,如果新增加理财业务,直接继承IBankStaffWork实现理财职员类即可,无需修改任何代码,只需要添加一个类,然后就可以在演示流程中使用。在修改方案中增加了客户选择业务的功能,也就是要求客户方必须得知道将要操作的业务。此方案同时需要负责演示虚拟场景的程序员对银行的业务要有了解,方案的选择要具体情况具体分析。
总结
1、开放封闭原则,是最为重要的设计原则,里氏替换原则、单一职责原则、接口隔离原则等面向对象设计原则为开放封闭原则的实现提供保证。
2、可以通过模板方法模式(Template Method Pattern)和策略模式(Strategy Pattern)进行重构,实现对修改封闭、对扩展开放的设计思路。
3、封装变化,是实现开放封闭原则的重要手段,对于经常发生变化的状态一般将其封装为一个抽象。
4、拒绝滥用抽象,只将经常变化的部分进行抽象,这种经验可以从设计模式的学习与应用中获得。