导语:
本篇文章是最近看了设计模式方面的知识,记录下自己的阅读内容以及笔记,以备以后翻录!
前言
- 设计模式分为设计与模式两块,通常来说分为 6 大设计原则和 23 种模式,但随着后续研究者的发掘与探究,将来也会有一些新的设计模式出现!
- 在遇到开发难题时,可以借鉴这些设计模式!
- 在学习这些设计模式时,能结合自己以前做过的项目更好,可以自己一边思考以前自己写的代码不足之处,一边理解这些设计模式的规则要求!
一、单一职责原则
定义
单一职责原则( Single Responsibility Principle ):指有且仅有一个原因引起类的变更。
理解:尽可能的将对象划分成单一性的类别,使类的复杂性降低,实现什么职责都有清晰明确的定义。
实例
要求:设计一个用户信息管理的类!
接口 IUserBO ( Business Object 用户信息属性放在一个接口里)
1 | public interface IUserBO { |
接口 IUserBL ( Business Logic 用户信息逻辑处理放在一个接口里)
1 | public interface IUserBL { |
接口 IUserInfo ( 用户信息接口将上面两类接口融合为用户信息接口 )
1 | public interface IUserInfo extends IUserBL,IUserBO{ |
类 UserInfo ( 用户信息管理类,实现上面的接口 )
1 | public class UserInfo implements IUserInfo{ |
在以上实例中,我们定义了三个接口和一个类,接口 IUserInfo 继承了接口 IUserBO 与 IUserBL,这样设计将 IUserInfo 的接口细化了,将属性操作和逻辑操作分开,这也就是印证了单一职责原则,IUserBO只负责用户属性操作,IUserBL只负责用户信息的逻辑操作!这样使得整个代码清晰易读!便于扩展!
结论
在开发过程中设计类或接口时,尽量要将 这些类和接口的职责唯一、明确。这样在进行合作开发时,不仅自己能够快速明确自己的目的,其他合作开发的程序员也能够明白你的意思。这样同样也可以降低代码的耦合性,有利于后期代码的维护。
二、里氏替换原则
定义
里氏替换原则 ( Liskov Substitution Principle, LSP ):所有引用基类的地方必须能够透明地使用其子类的对象。
理解:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法,也尽量不要重载父类的方法。
实例
我们想实现两数字的相减的功能,用 A 类来实现,如下:
1 | class A{ |
运行结果:
1 | 100-50=50 |
后来,我们需要增加一个新的功能:完成两数相加,然后再与 100 求和,由类 B 来负责。
1 | class B extends A{ |
运行结果:
1 | 100-50=150 |
我们发现原本运行正常的相减功能发生了错误。原因就是 类 B 在给方法起名时无意中重写了父类的方法,造成所有运行相减功能的代码全部调用了类B重写后的方法,造成原本运行正常的功能出现了错误。
在本例中,引用基类 A 完成的功能,换成子类 B 之后,发生了异常。在实际编程中,我们常常会通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的几率非常大。如果非要重写父类的方法,比较通用的做法是:原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖、聚合,组合等关系代替。
结论
里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
- 子类中可以增加自己特有的方法。
- 当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
- 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
看上去很不可思议,因为我们会发现在自己编程中常常会违反里氏替换原则,程序照样跑的好好的。所以大家都会产生这样的疑问,假如我非要不遵循里氏替换原则会有什么后果?后果就是:你写的代码出问题的几率将会大大增加。