文/大大大大峰哥
概述
在Java设计模式中,我们通常在设计上面需要遵循六大原则
单一职责原则
单一职责原则的定义
单一职责原则是一个类,引起它变化的原因只有一个.
该原则提出的是一个理想期望,任务对象不应该承担太多的职责,实现专注,才能保证对象的高内聚;单一性则可以保住对象的细粒度.高内聚与细粒度有利于对象的重用.当一个类承担了太多的职责,会造成冗余代码.
注意:单一职责原则不是只要求我们为类定义一个职责,而是提醒我们在一个类中尽量让类负载少的职责,从而保证对象具有高内聚与细粒度.
有时候我们在写项目的时候,比如是一个自行车的类,我们按照自行车一般的属性方法将这个类完善完毕,之后我们又有一个需求就是这个自行车具有某某特殊属性或者方法的自行车.这个时候在我们没有学习Java设计模式之前,我们会将这个特殊属性或者方法直接写入自行车类中.但是这个单一职责原则下,我们可以选择重新创造一个类(负责扩展原有自行车功能),这样就不会改变原有的类.这样有什么好处:
- 降低类的复杂度
- 提高类的可读性
- 提高代码的可维护性和复用性
- 降低因变更而引起的风险
单一职责原则的应用
在我们学习JavaEE的时候,JavaEE中的分层框架就体现了这个原则,将整个系统安装职责的内聚分为不同的层,每一层有一个主要的功能,关注事物一致.
Presentation:表现层
Business:业务层
persistence: 持久层
Database:数据层
用我现在在写的项目来举例,Dao包中的类就是处理一些业务逻辑,DB包中就是一些数据库的增删改查.
里氏替换原则
大家不要看这个名字拗口,这个其实就是教我如何正确使用继承的.
里氏替换原则定义
如果对一个类型为S的对象o1,都有类型为T的对象o2,以S定义的所有程序P中所有的对象o1都替换成o2时,程序P行为没有发生变化,那么类型T是类型S的子类型.
打完上面的字我内心都是挣扎的,我感觉会有读者大声的说能不能说人话…其实这个里氏替换原则就是告诉我们什么是继承,如果你知道什么是继承,就可以直接跳过上面那段话...
注意:子类不能更改父类的访问权限
依赖倒置原则
依赖倒置原则的定义
- 高层模块不应该依赖底层模型,两者都依赖其抽象
- 抽象不依赖细节
- 细节应该依赖抽象
我翻译翻译…抽象类指抽象类与接口.细节指已实现的类.在我们的Java项目中对该原则的表现:
- 模块之间的依赖是通过
抽象
产生,实现类之间不发生
直接的依赖关系. - 接口或者抽象类
不依赖
实现类,实现类依赖
于接口或者抽象类.
这个原则也就是希望我们大量使用接口和抽象类,也可以理解成"面向接口编程OOD".依赖倒置原则可以减少类间的耦合性,提高系统稳定,降低并行开发引起的风险,提高可读性和可维护性.
依赖倒置原则的应用
上图只有IDriver与ICar之间存在依赖关系,而实现类中都没有直接关系,这就是依赖倒置原则的应用.
使用这个原则需要遵循几个规则:
-
每个类
应该都具有接口或抽象类,或者同时具备抽象类和接口. - 变量的表面类型尽量是接口或者是抽象类
- 任何类都不应该从具体类派生
- 尽量不应该重写基类的方法
- 结合里氏替换原则使用
依赖倒置原则是六中设计原则中最难以实现的原则,它是实现开闭原则的重要途径.在项目中抓住"面向接口编程"的思想就基本抓住了依赖倒置的原则
接口隔离原则
这里先理解什么是接口.接口分为两种:
- 实例接口:Person 张三=new Person(),在这里的张三就是Person的实例接口
- 类接口:在我们使用多线程的时候,大家肯定发现有一个接口叫做java.lang.Runnable这个就是一个类接口.
接口隔离原则的定义
- 客户端不应该依赖它不需要的接口.
- 类间的
依赖关系
应该建立在最小的接口上.
接口相当于一个角色,我们不应该将不同的角色都交给一个接口.同时不应该强迫客户依赖于他们不用的方法,这一点十分重要.
在我们日常编码的过程中一个类,往往会有不同性质的对象,比如一个汽车,可能有奔驰,宝马,凯德拉克,特使拉等等,这些不同的车有一些不同的特性,对待这些不同的特性我们应该对应每一个不同的品牌写不同的接口.
接口隔离原则的应用
上面的应用实践可以看出一个接口只对一个子模块或者业务逻辑进行服务.这里还要提醒接口不是越小越好,接口太小则会导致接口数量剧增,给开发带来难度;如果接口太大,灵活性降低,将无法提供定制服务,给项目带来无法预计的风险.
迪米特法则
迪米特法则的定义
国外的定义往往通常是以发现者的名字所取名的,这个法则又叫做最少只是原则,其意义是:一个对象应当对其他对象尽可能的少的了解,其中对迪米特法则最具有代表性的几种表述如下:
- 只同你直接的朋友们通信
- 不要跟陌生人说话
- 每一个软件单位对其他的单位都只有最少的了解,这些了解仅局限于那些与本单位密切相关的软件单位
其实意义就是两个类之间的联系是通过一个朋友类
相互关联,这样可以减少类之间的关系,降低类之间的耦合,提高类的复用率.
迪米特法则的应用
我通过call方法传递进我的Friend,然后同Friend中的变量Stranger,我可以间接访问Stranger中方法,这样Friend就是一个类似介质的功能.
这里我对这个法则的感悟不是很深,暂时先记住,以后在后续的开发过程中可能可以找到这个法则的应用场景,和一些优点.
开闭原则
开闭原则的定义
一个软件应当对扩展开放,对修改关闭.
在设计一个模块的时候,应当使用这个模块可以在不被修改的前提下被扩展.面向对象编程中,开闭原则是最基本的原则,其他五大原则(单一职责,迪米特原则,里氏替换原则,依赖倒置原则,接口隔离原则)这些都是开闭原则的具体形态,以及是开闭原则的手段和工具.开闭原则一般可以通过以下几个方面体现:
- 开闭原则提高复用性
- 开闭原则提高可维护性
- 开闭原则提高灵活性
- 开闭原则有利测试
开闭原则的应用
上图是一个书店商品正常情况下的类.因为商店的促销需要来一个打折,所以在之前类通过继承的方式解决了这个问题.
这个就是开闭原则的体现对扩展开放,对修改关闭,我没有修改之前的代码,同时实现了功能的扩展,这是面向对象编程中至关重要的.
开闭原则解决问题的关键在与抽象化
.把所有可能的行为抽象为抽象底层,这个抽象底层规定了所有的具体实现必须提供的方法的特征,给系统定义一个一劳永逸的抽象设计,设计允许有无穷尽的行为在实现层被实现.
在抽象层一定要竟可能的预见所有可能的扩展,在任何扩展情况下的系统的抽象底层不需修改,从而满足开闭原则的第二条(对修改关闭).通过从抽象层导出一个或多个新的具体类改变系统的行为,通过使用新的行为来扩展,从而满足开闭原则的第一条(可以扩展).