参考资料:
本文参考资料是: 黑马程序员的视频教程 + 对应的课件资源,资源的地址如下,鼠标左键单击即可获取。
本文的内容: 是我对于六个软件设计原则的理解。
如果有啥错误,或者是课件资源链接失效,可以在评论区提出。
软件设计原则的个人理解: 面向单一职责接口编程(开闭、里氏替换、依赖倒转、接口隔离)+ 高度封装实体类(迪米特)+ 多用关联少用继承(合成复用)
官方解释:对扩展开放,对修改关闭。 在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。
简而言之:使用接口和抽象类, 当需要对模块进行扩展的时候,只需要新增一些实现类就能实现。
分析: 我现在有个动物叫声的接口:AnimalCalls ,现在我这个模块有猫的叫声和狗的叫声。
而现在,我想要向这个模块中加入兔子的叫声,我只需要新加一个实体类 Rabbit 去继承 AnimalCalls 并重写一下 call() 就可实现,只是在 AnimalCalls 的 call() 上去进行了扩展,并没有改写 call() 的内容(因为它是一个抽象方法,没有内容)。
官方解释:任何基类可以出现的地方,子类一定可以出现。
简而言之:子类可以扩展父类的功能,但不能改变父类原有的功能。 就是子类尽量别去重写父类的方法,这样就能保证:父类使用的地方,子类也能使用,因为子类只是在父类的基础上新增了功能,所有子类可以使用父类的所有功能。而为了实现这种效果,就是让子类实现接口。
分析: 经典案例 List
、Map
,打开源码或者查看API文档就能体会到了,这里就不做过多解释了。
官方解释:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。
这里,来对上面提到的几个名词做一下解释:
简而言之:对抽象进行编程,而不是对实现进行编程, 降低客户与实现模块之间的耦合度。
分析: 现在我要组装一件商品,他需要两种零件(A和B),而这两种零件分别有两种品牌(GuA、CastB)。那么直接用实现类实现就是这样的:
而现在,又有一种新的品牌(ByteA)进入市场,它比起GuA有着更低的售价,所以我决定要替换掉GuA,那么我首先得和GuA断绝联系,再使用ByteA,如下:
这样就显得过程很繁琐。
那来看一下使用接口的方案:
这样,就能很轻松地根据市场行情切换我想要使用的零件品牌。
官方解释:不应强迫客户端依赖它不使用的方法。
简而言之:使接口的行为单一, 也就是一个接口只专注于一个功能(一个方法,或者没有方法)。
分析: 经典案例:
java.io.Serializable
这个接口啥方法都没有,它的作用就是证明实现它的实体类可以进行序列化java.lang.Comparable
这个接口就只有一个方法compareTo
,只专注于实体类的排序java.lang.Cloneable
这个接口没有方法,它的作用就是声明实现类可以调用Object.clone()
对实体类的实例进行克隆好了,看完这三个经典案例,想必大家就已经了然于心了。
官方解释:一个类对于其他类知道的越少越好, 一个对象应当对其他对象有尽可能少的了解,只和朋友通信,不和陌生人说话。
这里,来对上面提到的几个名词做一下解释:
简而言之: 一个对象应当对其他对象有尽可能少的了解,只和朋友通信,不和陌生人说话。其目的是降低类之间的耦合度,提高模块的相对独立性。
分析: 房主把房子交给中介,让中介与租户联系实现房屋出租就能很好解释这个法则:
上述案例的具体实现可观看我的博客:代理模式(静态代理、jdk动态代理、CGLib动态代理),好的,这一段就到这里吧。
官方解释:尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。
简而言之: 继承具有很多缺点,建议使用组合或聚合。
分析:
上述案例的具体实现代码可以去看这篇文章:设计原则之合成复用原则,这里我就懒得写了。
好了,这篇文章就到此结束吧。