开放封闭原则(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、拒绝滥用抽象,只将经常变化的部分进行抽象,这种经验可以从设计模式的学习与应用中获得。