实验一
下图展示了一个简单的不遵循OCP的设计。Client类和Server类都是具体类。Client类使用Server类。如果我们希望Client对象使用另外一个不同的服务器对象,那么就必须要把Client类中使用Server类的地方更改为新的服务器类。
遵循OCP的原则修改上面的设计。在新的设计中,要设计一个新的ClientInterface 接口,Client类使用这个接口。
解析(参考):
在这个设计中,Clientinterface 类是一个拥有抽象成员函数的抽象类。Client 类使用这个抽象接口;然而 Client 类的对象却使用 Sever 类的派生类的对象。如果我们希望 Client 对象使用一个不同的服务器类,那么只需要从 Clientinterface 类派生个新的类。无需对 Client 类做任何改动。
实验二
在某客户关系管理系统(CRM)中可以使用不同的方式显示图标,如饼状图和柱状图邓,原始设计方案如下图所示。
类ChartDisplay中的display()方法代码如注释所示。
上面的设计违反了开闭原则。如果需要增加一个新的图表类,比如折线图 LineChart,则需要修改 ChartDisplay 类的 display() 方法的源代码。
现使用开闭原则对其进行重构。
解析(参考):
在本实例中,由于在 CharDisplay 类的 display() 方法中针对每一个图表类编,因增加新的图表类不得不修改源代码。我们可以通过抽象化的方式对系统进行重构,增加新的图标类时无需修改源代码,满足开闭原则。具体作法如下:
(1)增加一个抽象图表类 AbstracrChart,将各种具体图表类作为其子类;
(2)ChariDisplay 类针对抽象图表类进行编程,由客户端来决定使用哪种具体图表。
我们引人了抽象图表类 AbstractChart,且 ChartDisplay 针对抽象图表进行编程,并通过 setChart() 方法由客户端来设置实例化的具体图表对象。在 ChartDisplay 的 display() 方法中调用 chart 对象的 display() 方法显示图表。如果需要增加一种新的图表,如折线图 LineChart,只需要将 LineChart 也作为 AbstractChart 的子类,在客户端中 ChartDisplay 注人一个 LineChart 对象即可,无须修改现有类库的源代码。
在实际开发时,客户端也可以针对抽象的 AbstraciChart 编程,而将具体的图表类类名存储在配置文件(如XML 文件)中,通过 DOM和反射等技术来读取配置文件并反射生成对象,无须修改客户端代码,只要修改配置文件即可实现更换具体图表类,完全符合开闭原则