参考慕课网视频《Java设计模式精讲》:
视频作者:Geely
视频链接:https://coding.imooc.com/lesson/270.html#mid=17151
定义
不要存在多于一个导致类变更的原因。一个类、接口、方法只负责一项职责。
优点
降低类的复杂度、提高类的可读性,提高系统的可维护性、降低变更引起的风险。
代码实现
下面就以一个故事切入话题。
清风先生的朋友自制了一款MP4播放器,并且刻上了他女朋友的照片。大家都知道MP4既能播放音乐,又可以看小电影。满心欢喜的清风先生想将这么好的东西送给他的女朋友。
public interface MobileDevice {
/**
* //TODO 放音乐
* @param deviceName 设备名称
* @return void
*/
void playMusic(String deviceName);
/**
* //TODO 放电影
* @param deviceName 设备名称
* @return void
*/
void playMovie(String deviceName);
}
public class Mp4Device implements MobileDevice {
@Override
public void playMusic(String deviceName) {
System.out.println(deviceName + "我会播放音乐啊");
}
@Override
public void playMovie(String deviceName) {
System.out.println(deviceName + "我能播放电影啊");
}
}
清风先生的女朋友收到这个礼物,非常开心。到处炫耀自己的男朋友有多棒,多好。但是,过了一段时间。女朋友生气了。回到家对清风说:“你看隔壁小张,她的那个什么MP3音质可好了,你也知道,我平时都只是听听音乐,都不看什么电影的。就是喜欢沉浸在音乐的世界里。感觉MP4没她MP3的音质好啊。所以,我不开心了,你想办法解决,不然晚上回来跪键盘。”
清风先生听到了“跪键盘”,那一阵哆嗦啊。就立马跑去找朋友。然后,清风的朋友根据需求,重新制作了一个MP3。
(以下就用简洁的代码实现)
public interface MobileDevice {
/**
* //TODO 放音乐
* @param deviceName 设备名称
* @return void
*/
void playMusic(String deviceName);
}
public class Mp3Device implements MobileDevice {
@Override
public void playMusic(String deviceName) {
System.out.println(deviceName + "我会播放音乐啊");
}
}
清风先生又屁颠屁颠的把MP3送给了女朋友,但是好景不长。科技在进步,时代在变迁。MP5横空出世,在MP3、MP4的基础上增加了拍照的功能。大家都知道,女生就是喜欢拍照。没办法,可苦了自己了。
于是,又跑到朋友那里去,想要一个MP5。这次他朋友生气了,说:“你上辈子是产品经理啊,时不时改需求,改需求,算了,友尽吧!”
清风疑惑的问:“产品经理?what? what is this? 就让你弄一个能拍照的MP5就这么麻烦吗?以前不都有播放音乐、播放视频的功能吗?直接拿来用不就行了。”
他朋友说:“上次给你改MP3,我直接把播放电影的功能给删了。现在又要重新写。你真的是时不时来烦我,再有下次,看我网购一把西瓜刀。”
清风忽然明白了什么:给了他朋友一个脑瓜崩,说:“你傻啊,不会把每个功能,按照它的职责分离出来嘛?要是下次我家那位又不想要MP5了,又想用MP4了或者搞些别的骚东西,你是不是又要改来改去啊,这样重复造轮子,有意思吗?”
朋友哇哇大哭:“真是一语惊醒梦中人啊!不愧为我的好基友,刚才说的友尽都是气话。”
好了故事就是这样。上面的案例讲的就是违背了单一职责原则的设计,每次改动,都会让接口的实现类、以及接口发生变化。若是接口的实现类很多,所有类都会发生变动。系统的可维护性就会很差。需求变更会引起很大的风险。
接下来遵循单一职责原则,重写代码。
public interface IMovie {
void playMovie(String deviceName);
}
public interface IMusic {
void playMusic(String deviceName);
}
public interface IPhotoGraph {
void playGraph(String deviceName);
}
public class Mp5Device implements IMusic, IMovie, IPhotoGraph {
@Override
public void playMusic(String deviceName) {
System.out.println(deviceName + "我会播放音乐");
}
@Override
public void playGraph(String deviceName) {
System.out.println(deviceName + "我会拍照");
}
@Override
public void playMovie(String deviceName) {
System.out.println(deviceName + "我会播放电影");
}
}
上面就是遵循单一职责原则的设计,不管朋友制作MP3、MP4还是MP5。只管实现单一功能的接口就行了,实现什么职责都有明确的定义。这样不仅能提高可读性,降低类的复杂性,最重要的就是,代码更易维护。
用一个小例子讲了单一职责原则,虽然单一职责原则很棒,但是,还是要根据项目的实际情况和人员、成本出发。过分遵循单一职责,会造成类爆炸的情况,还会加深系统的复杂性。所以,软件设计既要考虑设计原则,还应该考虑实际情况。
活着就是为了改变世界,难道还有其他原因吗?