设计原则之开闭原则

定义:一个软件实体(类、模块或函数)应当对扩展开放,对修改关闭。
   也就是说软件实体应尽量在不修改原有代码的情况下进行扩展。

问题:在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,
   也可能会使我们不得不对整个功能进行重构,并且需要重新测试。

方案:当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。

举个栗子:这是一个包工头和工人的故事。。。

情况一:包工头给工人命名编号。具体实现方式如下:

1. 新建一个工人接口IWorker,包含一个工人编号的方法。代码如下:

       

2. 新建一个工人类Worker,来实现上面的IWorker接口方法。代码如下:

       

3. 新建一个包工头类Manager,包含一个给工人命名编号的方法,依赖IWorker接口。代码如下:

       

4. 在类OCPFragment中使用Worker对象调用命名编号的方法来实现功能。代码如下:

       

5. 运行后的效果,如下:

       

  以上的实现方式,成功完成了给工人命名编号的方法。现在我们要新增一个给工人分配角色和任务的功能,如果在现有代码的基础上作修改的话,比如在IWorker接口新增工人角色role()和工人任务doing()两个方法,在工人类Worker中去实现,修改包工头类Manager中的nameWorker()方法,这样做,如果多处调用了nameWorker()方法的话,很可能会造成原有功能发生故障,所以这时我们必须遵守开闭原则,对修改关闭、对扩展开发,不去修改原有的nameWorker()方法,而是去新增一个专门用于给工人分配角色和任务的方法,这样不仅不会影响到原有的功能,还提高了代码的复用性,更加灵活。

情况二:包工头给工人命名编号,给工人分配角色和任务。遵守开闭原则,具体实现方式如下:

1. 在IWorker接口中新增工人角色role()和工人任务doing()两个方法。代码如下:

       

2. 工人类Worker需要去实现新增的两个方法。代码如下:

       

3. 在包工头类Manager中新增一个给工人分配角色和任务的方法,依然依赖IWorker接口。代码如下:

       

4. 在类OCPFragment中仍使用Worker对象去调用allocateTask()方法来实现功能。代码如下:

       

5. 运行后的效果,如下:

       

  综上所述,如果一个软件系统符合开闭原则,那么从软件工程的角度来看,它将具有可复用性好和可维护性好两大特点。开闭原则是面向对象设计中“可复用设计”的基石,是面向对象设计中最重要的原则之一。

原则:
1. 通过接口或抽象类约束扩展,对扩展进行边界限定;
2. 参数类型、引用对象尽量使用接口或者抽象类,而不是实现类;
3. 抽象层尽量保持稳定,一旦确定就不允许修改;
4. 将相同的变化封装在一个接口或抽象类中;
5. 将不同的变化封装到不同的接口或抽象类中。

总结:
1. 单一职责原则要求实现类要职责单一;
2. 里氏替换原则要求不要去破坏继承系统;
3. 依赖倒置原则要求面向接口编程;
4. 接口隔离原则要求在设计接口的时候要精简单一;
5. 迪米特法则要求要降低耦合;
6. 开闭原则是总纲,要求对扩展开发,对修改关闭。
posted @ 2017-04-05 16:37  chenxkang  阅读(4753)  评论(0编辑  收藏  举报