最近学习设计模式六大原则,简单记录一下学习内容,方便以后复习查阅,如有理解的不对请评论指正。设计模式可以简单理解为面向对象语言开发过程中,遇到各种场景和问题,解决方案和思路。设计模式六大原则为:单一职责原则、里氏替换原则、迪米特法则、依赖倒置原则、接口隔离原则、开闭原则。
里式替换原则是用来帮助我们在继承关系中进行父子类的设计。
里氏替换原则(Liskov Substitution principle)是对子类型的特别定义的. 为什么叫里式替换原则呢?因为这项原则最早是在1988年,由麻省理工学院的一位姓里的女士(Barbara Liskov)提出来的。
里氏替换原则主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中蕴含的原理。里氏替换原是继承复用的基础,它反映了基类与子类之间的关系,是对开闭原则的补充,是对实现抽象化的具体步骤的规范。
里式替换原则有两层定义:
定义1
If S is a subtype of T, then objects of type T may be replaced with objects of type S, without breaking the program。
如果S是T的子类,则T的对象可以替换为S的对象,而不会破坏程序。
定义2:
Functions that use pointers of references to base classes must be able to use objects of derived classes without knowing it。
所有引用其父类对象方法的地方,都可以透明的替换为其子类对象
这两种定义方式其实都是一个意思,即:应用程序中任何父类对象出现的地方,我们都可以用其子类的对象来替换,并且可以保证原有程序的逻辑行为和正确性。
里氏替换原则是针对继承而言的,如果继承是为了实现代码重用,也就是为了共享方法,那么共享的父类方法就应该保持不变,不能被子类重新定义。子类只能通过新添加方法来扩展功能,父类和子类都可以实例化,而子类继承的方法和父类是一样的,父类调用方法的地方,子类也可以调用同一个继承得来的,逻辑和父类一致的方法,这时用子类对象将父类对象替换掉时,当然逻辑一致,相安无事。
如果继承的目的是为了多态,而多态的前提就是子类覆盖并重新定义父类的方法,为了符合LSP,我们应该将父类定义为抽象类,并定义抽象方法,让子类重新定义这些方法,当父类是抽象类时,父类就是不能实例化,所以也不存在可实例化的父类对象在程序里。也就不存在子类替换父类实例(根本不存在父类实例了)时逻辑不一致的可能。
不符合LSP的最常见的情况是,父类和子类都是可实例化的非抽象类,且父类的方法被子类重新定义,这一类的实现继承会造成父类和子类间的强耦合,也就是实际上并不相关的属性和方法牵强附会在一起,不利于程序扩展和维护。
采用里氏替换原则就是为了减少继承带来的缺点,增强程序的健壮性,版本升级时也可以保持良好的兼容性。即使增加子类,原有的子类也可以继续运行。
public class People { public int Id { get; set; } public string Name { get; set; } public void Traditional() { Console.WriteLine("仁义礼智信"); } } public class Chinese : People { public string Kuaizi { get; set; } public void SayHi() { Console.WriteLine("早上好,吃了吗?"); } } public class Hubei : Chinese { public string Majiang { get; set; } public new void SayHi() { Console.WriteLine("早上好,过早了吗?"); } }
三个类依次继承,湖北人继承自中国人,中国人继承自人。
Chinese people1 = new Chinese(); people1.Traditional(); Chinese people2 = new Hubei(); people2.Traditional();
people2使用的new Hubei()替代了people1等号右侧代码 new Chinese(),实现子类替换父类。
下面说说,子类替换父类后,如果子类与父类的方法一样,是调用父类的方法还是调用子类的方法,调用原则是什么?首先看下面定义的类,一个父类一个子类。
public abstract class ParentClass { public void CommonMethod() { Console.WriteLine("ParentClass CommonMethod"); } public virtual void VirtualMethod() { Console.WriteLine("ParentClass VirtualMethod"); } public virtual void VirtualMethod(string name) { Console.WriteLine("ParentClass VirtualMethod"); } public abstract void AbstractMethod(); } public class ChildClass : ParentClass { public new void CommonMethod() { Console.WriteLine("ChildClass CommonMethod"); } public void CommonMethod(string name) { Console.WriteLine("ChildClass CommonMethod"); } public override void VirtualMethod() { Console.WriteLine("ChildClass VirtualMethod"); } public override void VirtualMethod(string name) { Console.WriteLine("ChildClass VirtualMethod"); } public override void AbstractMethod() { Console.WriteLine("ChildClass AbstractMethod"); } }
调用代码如下:
ParentClass instance = new ChildClass(); instance.CommonMethod(); //普通方法由左边决定,编译时决定 instance.VirtualMethod(); //虚方法由右边决定,运行时决定 instance.AbstractMethod();//抽象方法由右边决定,运行时决定
执行结果如下:
通过执行结果可以看出,调用原则如下:
2、虚方法由右边决定,运行时决定
3、抽象方法由右边决定
- 2025年3月 (1)
- 2024年6月 (2)
- 2024年5月 (2)
- 2024年4月 (4)
- 2024年3月 (30)
- 2024年1月 (4)
- 2023年12月 (2)
- 2023年11月 (4)
- 2023年10月 (4)
- 2023年9月 (6)
- 2023年3月 (2)
- 2023年2月 (1)
- 2023年1月 (1)
- 2022年12月 (1)
- 2022年9月 (21)
- 2022年8月 (10)
- 2022年7月 (3)
- 2022年4月 (1)
- 2022年3月 (13)
- 2021年8月 (1)
- 2021年3月 (1)
- 2020年12月 (42)
- 2020年11月 (7)
- 2020年10月 (5)
- 2020年8月 (1)
- 2020年6月 (1)
- 2020年3月 (2)
- 2019年12月 (8)
- 2019年11月 (3)
- 2019年9月 (1)
- 2019年4月 (1)
- 2019年3月 (6)
- 2019年2月 (1)
- 2018年7月 (7)
- 1.asp.net mvc内微信pc端、H5、JsApi支付方式总结(5703)
- 2.各大搜索网站网站收录提交入口地址(3202)
- 3.Windows 10休眠文件更改存储位置(3167)
- 4.ECharts仪表盘实例及参数使用详解(3096)
- 5.windows 10安装myeclipse 10破解补丁cracker.jar、run.bat闪退解决办法(2995)
- 6.HTML5 WebSocket与C#建立Socket连接实现代码(2867)
- 7.华为鸿蒙系统清除微信浏览器缓存方法(2793)
- 8.CERT_HAS_EXPIRED错误如何解决(2261)
- 9.Js异步async、await关键字详细介绍(lambda表达式中使用async和await关键字)(2192)
- 10.HBuilder编辑器格式化代码(2120)