单一职责原则
开-闭原则--OCP
原文:https://www.cnblogs.com/landeanfen/p/5272144.html
开放封闭原则主要体现在对扩展开放、对修改封闭,因为需求变更,运行环境升级等原因需要改代码,如果没有出现bug,那么不推荐改原来的代码,可以在原基础上进行扩充。既增加了扩展性,又保证原来的逻辑不出问题。
系统设计需要遵循开闭原则的原因
1.稳定性。开闭原则要求扩展功能不修改原来的代码,这可以让软件系统在变化中保持稳定。
2.扩展性。开闭原则要求对扩展开放,通过扩展提供新的或改变原有的功能,让软件系统具有灵活的可扩展性。
遵循开闭原则的系统设计,可以让软件系统可复用,并且易于维护。
场景实例
非开闭原则
1 EmailMsg工具类
namespace OCP { /// <summary> /// 发邮件的类 /// </summary> class EmailMsg { /// <summary> /// 发送信息方法 /// </summary> /// <param name="str">内容</param> public void SendMsg(string str) { Console.WriteLine("Eamil问候:" + str); } } }
2 MsgService服务
namespace OCP { class MsgService { EmailMsg emailHandle = null; public MsgService() { emailHandle = new EmailMsg(); //构造函数中实例化EamilMsg } /// <summary> /// 节日祝福 /// </summary> /// <param name="str"></param> public void Greeting(string str) { emailHandle.SendMsg(str); } } }
3 业务调用模块
/************************************************ * OCP:开闭原则 * * **********************************************/ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace OCP { class Program { static void Main(string[] args) { MsgService ms = new MsgService(); //实例化消息管理MsgService类 ms.Greeting("祝大家节日快乐"); Console.ReadKey(); } } }
现在需求变动,公司发现邮件推送的方式也存在一些弊病,比如某些网络不发达地区不能正常地收到邮件,并且在外出差人员有时不能正常收到邮件。这个时候公司领导发现短信推送是较好的解决办法。于是乎,需求变更来了:增加短信推送节日祝福的功能,对于行政部等特殊部门保留邮件发送的方式。
研发部的同事们虽然已有微言,但是没办法,也只有咬着牙忙了,于是代码变成了这样。
1 工具类里面增加了发送短信的帮助类
namespace OCP { /// <summary> /// 发邮件的类 /// </summary> class EmailMsg { /// <summary> /// 发送信息方法 /// </summary> /// <param name="str">内容</param> public void SendMsg(string str) { Console.WriteLine("Eamil问候:" + str); } } /// <summary> /// 添加发短信的类 /// </summary> class PhoneMsg { public void SendMsg(string str) { Console.WriteLine("短信问候:" + str); } } }
2 MsgService服务里面增加了一个枚举类型MsgType判断是哪种推送方式
namespace OCP { /// <summary> /// 添加枚举判断消息类型 /// </summary> public enum MsgType { Email, Phone } class MsgService { EmailMsg emailHandle = null; //邮件工具对象 PhoneMsg phoneHandle = null; //短信工具类对象 MsgType m_type; //消息种类 /// <summary> /// 构造函数 /// </summary> /// <param name="oType">构造时给的消息的种类</param> public MsgService(MsgType oType) { m_type = oType; switch (m_type) { case MsgType.Email: emailHandle = new EmailMsg(); //构造函数中实例化EamilMsg break; case MsgType.Phone: phoneHandle = new PhoneMsg(); //实例化PhoneMsg对象 break; } } /// <summary> /// 节日祝福 /// </summary> /// <param name="str"></param> public void Greeting(string str) { switch (m_type) { case MsgType.Email: emailHandle.SendMsg(str); //发送邮件祝福 break; case MsgType.Phone: phoneHandle.SendMsg(str); //发送短信祝福 break; } } } }
3 业务调用模块
/************************************************ * OCP:开闭原则 * * **********************************************/ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace OCP { class Program { static void Main(string[] args) { MsgService ems = new MsgService(MsgType.Email); //实例化发邮件的消息管理MsgService类 ems.Greeting("祝大家节日快乐"); MsgService pms = new MsgService(MsgType.Phone); //实例化发短信的消息管理MsgService类 pms.Greeting("祝大家节日快乐"); Console.ReadKey(); } } }
结果:
随着公司的不断发展,很多产品、平台都融入了微信的功能,于是乎公司领导又希望在保证原有功能的基础上增加微信的推送方式。事情发展到这里,就可以看出使用实现类去编程,你会因为需求变更而死得很惨,这个时候我们就能看出遵守开闭原则的重要性了,如果这个系统设计之初就能考虑这个原则,所有的可变变量使用抽象去定义,可能效果截然不同。
开闭原则实现
1 工具类
项目设计之初我们定义一个ISendable接口
namespace OCP { interface ISendable { void SendMsg(string str); } }
namespace OCP { /// <summary> /// 发邮件的类 /// </summary> class EmailMsg:ISendable { /// <summary> /// 发送信息方法 /// </summary> /// <param name="str">内容</param> public void SendMsg(string str) { Console.WriteLine("Eamil问候:" + str); } } /// <summary> /// 添加发短信的类 /// </summary> class PhoneMsg:ISendable { public void SendMsg(string str) { Console.WriteLine("短信问候:" + str); } } /// <summary> /// 添加发送微信的类 /// </summary> class WechatMsg : ISendable { public void SendMsg(string str) { Console.WriteLine("微信问候:" + str); } } }
2 MsgService服务
namespace OCP { /// <summary> /// 添加枚举判断消息类型 /// </summary> public enum MsgType { Email, Phone } class MsgService { //EmailMsg emailHandle = null; //邮件工具对象 //PhoneMsg phoneHandle = null; //短信工具类对象 //MsgType m_type; //消息种类 ISendable sendHandle = null; public MsgService(ISendable oSendHandle) //构造时传入不同发消息的工具类的实例 { sendHandle = oSendHandle; } //节日祝福 public void Greeting(string str) { sendHandle.SendMsg(str); } } }
3 业务调用模块
/************************************************ * OCP:开闭原则 * * **********************************************/ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace OCP { class Program { static void Main(string[] args) { //MsgService ems = new MsgService(MsgType.Email); //实例化发邮件的消息管理MsgService类 //ems.Greeting("祝大家节日快乐"); //MsgService pms = new MsgService(MsgType.Phone); //实例化发短信的消息管理MsgService类 //pms.Greeting("祝大家节日快乐"); string str = "祝大家节日快乐"; ISendable em = new EmailMsg(); MsgService ems = new MsgService(em); ems.Greeting(str); ISendable pm = new PhoneMsg(); MsgService pms = new MsgService(pm); pms.Greeting(str); ISendable wm = new WechatMsg(); MsgService wms = new MsgService(wm); wms.Greeting(str); Console.ReadKey(); } } }
里氏转换原则
依赖倒置原则-DIP
原则定义:
1.高层模块不应该依赖低层模块,两者都应该依赖其抽象(接口);抽象(接口)不应该依赖细节(实现类),细节(实现类)应该依赖抽象(接口)。
2.要针对接口编程,不要针对实现编程
简单来说,调用的模块可以看作是高层模块,,而被调用的模块是低层模块。中间的可以看作是过渡模块。
比如:a调用b,b调用c,c调用d,那么a就是高层模块,而d时低层模块。
被“倒置”的依赖
相比传统的软件设计架构,比如我们常说的经典的三层架构,UI层依赖于BLL层,BLL层依赖于DAL层。由于每一层都是依赖于下层的实现,这样当某一层的结构发生变化时,它的上层就不得不也要发生改变,比如我们DAL里面逻辑发生了变化,可能会导致BLL和UI层都随之发生变化,这种架构是非常荒谬的!好,这个时候如果我们换一种设计思路,高层模块不直接依赖低层的实现,而是依赖于低层模块的抽象,具体表现为我们增加一个IBLL层,里面定义业务逻辑的接口,UI层依赖于IBLL层,BLL层实现IBLL里面的接口,所以具体的业务逻辑则定义在BLL里面,这个时候如果我们BLL里面的逻辑发生变化,只要接口的行为不变,上层UI里面就不用发生任何变化。
经典的三层里面,高层模块直接依赖低层模块的实现,当我们将高层模块依赖于底层模块的抽象时,就好像依赖“倒置”了。这就是依赖倒置的由来。通过依赖倒置,可以使得架构更加稳定、更加灵活、更好应对需求变化。
2.3、依赖倒置的目的
上面说了,在三层架构里面增加一个接口层能实现依赖倒置,它的目的就是降低层与层之间的耦合,使得设计更加灵活。从这点上来说,依赖倒置原则也是“松耦合”设计的很好体现。
接口隔离原则
最少知识原则(迪米特法则)
少用继承多用组合(合成复用)
设计原则的作用
让设计出来的软件系统更加稳定,容易维护,并具有一致性