什么是单一职责原则?
单一职责原则(Simple Responsibility Principle,SRP)指不要存在一个以上导致类变更的原因,简单点来说就是一个类最好只负责一件事,只有一个引起它变化的原因。
案例分析
比如我们需要做一个动物类的app,里面有一个简单的功能,就是让所有的动物都拥有跑的功能,我们来看下设计思路:
1、首先我们定义一个动物类,让动物拥有一些属性以及行为
2、动物类都包含哪些属性和行为?比如跑这个行为。
3、我们捋清除了动物类的定义和行为,那我直接声明一个动物类,在动物类中增加一个跑的方法就可以了
方案一:初始设计
1、定义Animal类
定义一个run方法,让所有的动物都可以跑
1
2
3
4
5
class Animal{
void run(String name) {
print("$name 正在跑");
}
}
2、使用Animal
我们实例化了Animal,让平头哥、鱼、金丝雀都在跑
1
2
3
4
5
6
void main(List<String> args) {
Animal animal = Animal();
animal.run("平头哥");
animal.run("鲸鱼");
animal.run("金丝雀");
}
3、运行结果
1
2
3
4
5
Connecting to VM Service at http://127.0.0.1:49714/YfCcnIXloec=/
平头哥 正在跑
鱼 正在跑
金丝雀 正在跑
Exited
4、完整代码
1
2
3
4
5
6
7
8
9
10
11
12
void main(List<String> args) {
Animal animal = Animal();
animal.run("平头哥");
animal.run("鲸鱼");
animal.run("金丝雀");
}
class Animal{
void run(String name) {
print("$name 正在跑");
}
}
5、分析
代码运行到此处我们发现一个问题,平头哥跑很正常,但是鱼和金丝雀在跑属于有点说不过去了,也就是说run方法就违背了单一职责原则
方案二:抽象类(子类实现)
既然上面这种方式会违背单一职责原则,那么我们就把天上飞的、地下跑的、水里游的全部单独定义出来,我们具体来看下代码
1、定义抽象类Animal
该抽象类暴露了一个run方法,由子类去继承实现
1
2
3
abstract class Animal {
void run(String name);
}
2、定义海、陆、空
定义海、陆、空三个类来分别实现Animal,并实现自己的run方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 海
class SeaAnimal implements Animal {
@override
void run(String name) {
print("$name 正在游");
}
}
// 陆
class LandAnimal implements Animal {
@override
void run(String name) {
print("$name 正在跑");
}
}
// 空
class SkyAnimal implements Animal {
@override
void run(String name) {
print("$name 正在飞");
}
}
3、使用
当我们的动物不管是什么类型的调用对应的类就可以
1
2
3
4
5
6
7
8
9
10
void main(List<String> args) {
SeaAnimal seaAnimal = SeaAnimal();
seaAnimal.run("鲸鱼");
LandAnimal landAnimal = LandAnimal();
landAnimal.run("平头哥");
SkyAnimal skyAnimal = SkyAnimal();
skyAnimal.run("金丝雀");
}
4、运行结果
1
2
3
4
5
Connecting to VM Service at http://127.0.0.1:52373/S8UZZnTUCkI=/
鲸鱼 正在游
平头哥 正在跑
金丝雀 正在飞
Exited
5、完整代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void main(List<String> args) {
SeaAnimal seaAnimal = SeaAnimal();
seaAnimal.run("鲸鱼");
LandAnimal landAnimal = LandAnimal();
landAnimal.run("平头哥");
SkyAnimal skyAnimal = SkyAnimal();
skyAnimal.run("金丝雀");
}
abstract class Animal {
void run(String name);
}
// 海
class SeaAnimal implements Animal {
@override
void run(String name) {
print("$name 正在游");
}
}
// 陆
class LandAnimal implements Animal {
@override
void run(String name) {
print("$name 正在跑");
}
}
// 空
class SkyAnimal implements Animal {
@override
void run(String name) {
print("$name 正在飞");
}
}
6、分析
我们通过拆分类的方式进行了优化,这样就不违背的单一职责原则,这样做的好处在于不管是海、陆、空的任何动物都可以调用对应的类去进行操作。
方案三:定义不同运行方式
当我们使用方案二的时候,会发现,当我们对类需要进行变动的时候,那么需要同时修改多处地方,所以这种方案并不是最好的,所以我们来看一下最终方案(统一修改)
1、定义Animal类
定义Animal动物类,里面定义海、陆、空三种不同的运行方式
1
2
3
4
5
6
7
8
9
10
11
class Animal {
void runSky(String animal) {
print("$animal 正在飞");
}
void runSea(String animal) {
print("$animal 正在游");
}
void runLand(String animal) {
print("$animal 正在跑");
}
}
2、使用
我们通过不同的动物种类去调用对应的方法
1
2
3
4
5
6
void main(List<String> args) {
Animal animal = Animal();
animal.runSky("金丝雀");
animal.runLand("平头哥");
animal.runSea("正在游");
}
3、运行结果
1
2
3
4
5
Connecting to VM Service at http://127.0.0.1:52903/aKdnW0UroL0=/
金丝雀 正在飞
平头哥 正在跑
正在游 正在游
Exited
4、完整代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void main(List<String> args) {
Animal animal = Animal();
animal.runSky("金丝雀");
animal.runLand("平头哥");
animal.runSea("正在游");
}
class Animal {
void runSky(String animal) {
print("$animal 正在飞");
}
void runSea(String animal) {
print("$animal 正在游");
}
void runLand(String animal) {
print("$animal 正在跑");
}
}
5、分析
我们通过定义不同的方法,这样对原有类并没有做大的修改,只是增加方法。
这里值得一提的是方案三在类的级别上来说并没有去遵守单一职责原则,但是从方法级别上来说仍然是遵守了单一职责原则
总结
上面是单一职责原则的三种方案,在我看来,没有最合理,只有最合适的。三种方案都很好,只要能理解单一职责的划分,根据需求来对应使用即可。