目录
前言与文章介绍
文章将先阐释开放封闭原则,然后将理论运用于实践,讲解如何将开放封闭原则运用于实际项目(可拓展的对内封闭的技能管理系统)中,在最后将提供源码的下载
一、概念阐释
1、什么是开放封闭
在软件、程序设计的时候,追求的目标是达到封装变化、降低耦合,来实现高内聚低耦合。开放封闭原则正是对这一目标的最直接体现,而其他的设计原则,很多时候也是为实现这一目标服务的。
开放封闭原则(OCP,Open Closed Principle)是所有面向对象原则的核心
其核心的思想是:
软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。
因此,开放封闭原则主要体现在两个方面:
对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
2、开放封闭原则怎么实现
2.1 基本思路
我们需要让类依赖于固定的抽象,所以对修改就是封闭的;而通过面向对象的继承和多态机制,可以实现对抽象体的继承,通过覆写其方法来改变固有行为,实现新的扩展方法,所以对于扩展就是开放的。
仔细来说,在软件设计的过程中,必须考虑到在不需要对原有的系统进行修改的情况下,实现灵活的系统扩展,否则后期难以维护,而实现这一思路只有依赖于抽象。实现开放封闭的核心思想就是对抽象编程,而不对具体编程,因为抽象相对稳定。让类依赖于固定的抽象,所以对修改就是封闭的;而通过面向对象的继承和对多态机制,可以实现对抽象体的继承,通过覆写其方法来改变固有行为,实现新的扩展方法,所以对于扩展就是开放的。这是实施开放封闭原则的基本思路。
2.2 具体方法
对于违反这一开发封闭原则的类,必须进行重构来改善,而封装变化,是实现这一原则的重要手段,将经常发生变化的状态封装为一个类。
开放封闭原则其实是对单一职责原则的一个延伸,因为每个功能/类也应该只有一个发生变化的原因,应该用接口封装起变化。
那为什么一直在用接口实现这种方法呢?
使用接口的原因是接口可以被多重实现,抽象类abstrat只能被单一继承,更加适用于开放封闭原则中的可扩展。
在单一职责原则中,我们把类中的每一个方法都抽成一个接口,然后再继承接口,实现方法,再在类中写方法调用接口实现的方法,这虽然符合单一职责原则,就是在面向接口(面向抽象)编程,这样的封装其实不太现实,因为后期还会扩展方法,所以在这里采取的是一种总的功能做为一个接口,分功能继承这一接口即可。
抽象、封装不是目的,目的是封装变化,只有对变化封装了,我们的程序才能做到开放封闭原则
二、运用原则的实例说明
实现解释
1.基于开放封闭的原则,我设计并且实现了一个可拓展的对内封闭的技能管理系统,为了实现对扩展开放,我们需要让技能实现依赖于固定的抽象,通过覆写其方法,改变或者是实现固有的行为。
所以设置了IskillContain的接口(使用接口的原因是接口可以被多重实现,抽象类abstrat只能被单一继承,更加适用于开放封闭原则中的可扩展),设置固定的skillinvoke方法。之后所有的技能都继承于这个接口,代码实现如下
#region 技能拓展区具体实现
//技能实现方式为接口
public interface IskillContain
{
//执行技能
void skillInvoke();
}
public class initialskillClass : IskillContain
{
public void skillInvoke()
{
Debug.Log("初始技能实现");
}
}
public class middleskillClass : IskillContain
{
public void skillInvoke()
{
Debug.Log("中等技能实现");
}
}
public class highskillClass : IskillContain
{
public void skillInvoke()
{
Debug.Log("高阶技能实现");
}
}
#endregion
示意图如下
2.在封装好技能实现之后,接下来需要考虑如何具体的引用某个技能,一开始可能想到的是switch
case这样的分支语句,但是当技能对象增加,这样的语句在整体代码中会显得冗余,不符合原则的思想,所以在这里使用的是传入对象类型参数的方法,具体实现的思路是:通过接口定义一个需要返回IskillContain对象的方法,然后设置对应技能的类继承接口并实现方法,返回对应的技能实现对象,具体代码如下:
//用来实现获取对象的接口
public interface ISkillTypeGet
{
//根据不同的技能对象,实现不同的技能
IskillContain GetSkill();
//规定返回对象必须为技能类对象
}
//定义对应的类,实现返回功能
public class initialskillGet : ISkillTypeGet
{
public IskillContain GetSkill()
{
return new initialskillClass();
}
}
public class middleskillGet : ISkillTypeGet
{
public IskillContain GetSkill()
{
return new middleskillClass();
}
}
public class highskillGet : ISkillTypeGet
{
public IskillContain GetSkill()
{
return new highskillClass();
}
}
示意图如下
3.所以,只需要传入获取技能的对象,就可以定向的实现具体的技能。这里是实现了封装,为什么在这里要再次封装呢?因为在最终实现的目标中,技能管理方法需要对不同的对象处理其不同的实现方法,更直观的说,我们在实现技能对象获取的过程中,存在有不止是技能实现这一个功能的可能性,开放封闭原则就是要避免内部修改而允许扩展,如果没有封装,那么也会不符合单一职责的原则,管理方法实现代码如下:
public class SkillManager
{
//获得技能实现对象的引用
private IskillContain skillContain;
public void HandleProcess(ISkillTypeGet SkillGet)
{
//获得技能对象
skillContain = SkillGet.GetSkill();
//执行技能
skillContain.skillInvoke();
}
}
4.现在我们已经实现了获取技能、技能实现的基本功能,所以只需要在一开始创建具体的技能获取对象,再传入SkillManager即可实现,在开放封闭原则下的技能管理系统
//系统实现
private void Start()
{
//创建中等技能获取
ISkillTypeGet GetcurrentType = new middleskillGet();
//创建管理器
SkillManager skillManager = new SkillManager();
skillManager.HandleProcess(GetcurrentType);
}
实例总结
技能管理系统的总体结构示意图如下
将技能实现这一功能封装为一个总接口,技能获取对应技能实现,同时技能获取这一功能也封装为一个总接口,由最终由管理器调用启动。
扩展:不论是技能实现还是技能获取,其方法在接口中就已经定义好了可以任意根据需求拓展--创建新的技能类继承,或者是修改技能类内部具体的代码
封闭:技能实现、技能获取方法是固定的,只需要修改继承的类,不需要对接口进行任何修改
修改类增加类都不会对设计好的技能实现,技能获取的流程方法造成任何影响
如此就将开放封闭原则运用于实践,做到了“对扩展是开放的,而对修改是封闭的”。
三、相关链接
1.关于单一职责原则的阐释
单一职责原则(SOLID之一) 理解与实现 C#Unity_花火の云的博客-CSDN博客
2.开放封闭原则的实例代码