开放封闭原则,它规定了软件设计和维护时应该遵守的一种规则,即对扩展开放、对修改关闭。
扩展和修改不难理解,扩展指的是对原有的结构进行拓展,增加新的类让其继承父类、实现接口,利用多态、继承等特性进而实现新的功能。而修改在这里指的是更改那些已经投入使用的类尤其是抽象类和接口,包括增删改类方法及其实现步骤或参数,还有类的属性等。
面对功能的实现与可能的增改。对扩展开放意味着,通过扩展代码、增加新的类进行实现是允许和推荐的;而对修改关闭意味着,要尽可能地避免对源代码的修改。
合在一起说,就是在设计与维护时应尽可能的通过扩展而非修改原有结构来实现新的功能。
为了达到可便于修改这一要求,抽象是必不可少的,一个恰到好处的抽象总可以囊括即将到来的变化,当需求变化来临时只需要针对具体的变化扩展一个抽象的具体实现类,由于多态的特性很好的解决问题,同时也避免对原有代码的修改。可以说,对扩展开放”的关键是”抽象”,而对象的多态则保证了这种扩展的开放性(更具体的说,应该是里氏替换原则)。
这里可以引用上一篇讲述里氏替换原则的例子来说明这个原则:
实现:
class Bird { String name; Bird(String name){ this.name = name;} public void move() { System.out.println(name + " is flying~~~"); } } ... class Main { public static void main(String[] args) { Bird swallow= new Bird("swallow"); swallow.move(); } }
分析:最简单的想法是,像鸟类一样写一个狗类对象,更改主方法中的调用。但是这样的操作就违反了我们的开闭原则,我们对源码进行了修改,如果以后增加其他的动物类,那么主方法中语句就需要不断地修改(而若是这个类已经被大量使用,那么修改的规模和难度可就十分吓人了)。
因此这样的设计是需要进行优化的。应该将鸟类和狗类以及其他的可能出现的相似的类抽象成为动物类,拥有共同的行为和属性如移动和名称,这时再添加新的动物,派生新的子类即可。实例化时使用动物的引用也可以避免大量的修改。
修改后的代码:
abstract class Animal { protected String name; abstract public void move(); } class Bird extends Animal { Bird(String name){ this.name = name;} public void move() { System.out.println(name + " is flying~~~"); } } ... class Main { static public void main(String[] args) { Animal animal = new Bird("swallow"); animal.move(); } }
增加一个狗类并实例化对象
class Dog extends Animal { Dog(String name){ this.name = name;} public void move() { System.out.println(name + " is running~~~"); } } ... class Main { static public void main(String[] args) { Animal animal1 = new Dog("Husky"); Animal animal2 = new Bird("swallow"); animal1.move(); animal2.move(); } }
此时,如果再度增加需求,要求狗类拥有捕食行为以某个动物为捕食对象。
代码:
... interface Hunter//定义猎手接口 { public void hunt(Animal prey); } class Dog extends Animal implements Hunter//继承动物类并实现猎手接口 { Dog(String name){ this.name = name;} public void move() { System.out.println(name + " is running~~~"); } public void hunt(Animal prey)//具体的捕猎行为 { System.out.println(name + " has hunt " + prey.name); } } ... class Main { static public void main(String[] args) { Animal animal = new Bird("swallow"); animal.move(); Hunter hunter = new Dog("Husky"); hunter.hunt(animal); } }
在开闭原则中可以看到很多其他原则和设计模式的影子,这不是偶然。
开闭原则可以说是最根本的原则,其余的设计原则,可以看做是在这一大原则下分述某个具体的方向,且每个设计模式的的设计必须要遵循六大基本原则。
另外,开放封闭原则很好地保证了代码的可复用性和可维护性。但需要注意的是,设计要做到完全对修改封闭,这几乎是不可能完成的,因为需求是未知的,抽象又是根据需求和内容来设计的。因此,如要做出很好满足开闭原则的设计,需要设计者的经验和洞察力,这个过程必定伴随着不断地试错和学习。
最后,博主也是一个正在努力学习的萌新,因此对于这样的大原则一定会有拿捏不准的和遗漏的地方,如有疏漏,还请指出,我们共同学习。
系列文章参考资料:
设计模式系列文章:
面向对象 之 不能不知道的类间关系(上)泛化、实现、依赖 C++与Java
面向对象 之 不能不知道的类间关系(下)关联、聚合、组合 C++与Java
JAVA单例模式分析及其实现:饿汉式、懒汉式、双重检查、静态内部类
设计模式 之 迪米特法则
设计模式 之 里氏替换原则
设计模式 之 设计原则(1) 单一职责原则 接口隔离原则 依赖倒转原则