软件实体(类、模块、函数等)应该是能够扩展的,可是不可修改。服务器
若是正确的应用了OCP原则,那么 之后在进行一样的改动时,就只须要添加新的代码,没必要修改已经正常运行的代码。函数
1.对于扩展是开放的设计
这意味着模块的行为是能够扩展的。当应用的需求改变时,咱们能够对模块进行扩展,使其具备知足那些改变的新行为。换句话说,咱们能够改变模块的功能。对象
2.对于修改是封闭的blog
对模块进行扩展时,没必要改动模块的源代码或者二进制代码。接口
3.有何问题扩展
这两个特征好像是互相矛盾的。扩展模块行为的一般方式就是修改该模块的源代码。不容许修改模块经常都认为具备固定的行为。软件
4.如何实现?(抽象)二进制
怎么可能在不改动源代码的状况下去更改它的行为呢?若是不更改一个模块,又怎么可以去改变它的功能呢?方法
答案是抽象。在C#中,能够建立出固定却可以描述一组任意个可能行为的抽象体。这个抽象体就是抽象基类。而这一组任意个可能的行为则表现为可能的派生类。
模块可能对抽象体进行操做。因为模块依赖于一个固定的抽象体,因此它对于更改能够是封闭的。同时,经过从这个抽象体派生,能够扩展此模块的行为。
下图展现了一个简单的不遵循OCP的设计。Client类和Server类都是具体类。Client类使用Server类,若是咱们但愿Client对象使用另外一个不一样的服务器对象,那么就必需要把Client类中使用Server类的地方更改成新的服务器类。
下图则使用Strategy模式(策略模式)展现了一个针对上述问题的遵循OCP的设计。
下图展现了另外一个使用Template method模式(模版方法模式)的结构。
和图2中Client类的函数相似,Policy类具备一组实现了某个策略的具体公共函数。和前面同样,这些策略函数根据一些抽象接口描绘了要完成的功能,不一样的是,在这个结构中,这些抽象接口是Policy类自己的一部分。在C#中,它们是抽象方法。这些函数在Policy类子类型中实现。这样,能够经过从policy类派生出新类的方式,对Policy中指定的行为进行扩展。
在不少方面,OCP都是面向对象设计的核心所在。遵循这个原则能够带来面向对象技术所声称的巨大好处:灵活性、可重用性以及可维护性。
拒毫不成熟的抽象和抽象自己同样重要。