首页 学海无涯 程序设计 程序设计六大原则:单一职责原则
程序设计六大原则:单一职责原则
摘要 单一职责原则(SRP:Single responsibility principle)又称单一功能原则,面向对象五个基本原则(SOLID)之一。它规定一个类应该只有一个发生变化的原因。

单一职责原则(Single Responsibility Principle)(SRP)

定义

一个类或模块有且只有一个引起它改变的原因。如果一个类有一个以上的职责,这些职责就耦合在了一起。这会导致脆弱的设计。当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一起,会影响复用性。(摘自百度百科)

诞生原因

在面向对象的程序设计中,高内聚低耦合是判断程序设计好坏的标准。而一个类如果负责多个不同的职责,当其中某一个职责因为需求的改变而需要修改类时,可能导致其他职责的发生故障,这个类中的各个职责耦合在一起。所以在程序设计中应该尽量遵循单一职责原则,将不同的职责封装到不同的类或模块中。

案例讲解

初始需求:创建一个动物类,包含动物名称字段。

新需求:动物移动

不好的设计

internal class Animal
{
private string name = string.Empty;
// 初始需求
public void SetName(string name)
{
this.name = name;
}
// 新需求
public void Move()
{
Console.WriteLine($"{name} 行走");
}
}

上述代码,对新需求的应对看似没有什么问题,添加了一个方法移动(Move)。

这样做有什么缺点呢?如果我这个动物是鱼,那么很显然这个Move方法里的“行走”就需要替换成“游泳”,也就是说这个Move方法可能会因为动物的不同而导致实现代码的不同,每当我们新发现一种动物可能就会修改一下这个Animal类(如下):

public void Move()
{
if (name == "鱼")
{
Console.WriteLine($"{name} 游泳");
}
else if (name == "鸟")
{
Console.WriteLine($"{name} 飞行");
}
else
{
Console.WriteLine($"{name} 行走");
}
// ...每发现一个新物种,就需要修改一下Animal类
}

这样就违反了单一职责原则,动物的名称信息和动物的移动行为耦合在了Animal类中。

优化设计1

动物类应该只负责动物名称信息的职责,而动物移动的职责交给其他类,将二者分离开来,这样才叫单一职责。

类级别的单一职责

保留Animal类的基本信息:

internal class Animal
{
private string name = string.Empty;

public void SetName(string name)
{
this.name = name;
}
}

新建一个AnimalAction类:

public class AnimalAction {
public void Move(Animal animal);
}

把动物移动的职责交个AnimalAction类来处理,这样一来不仅仅满足了单一职责的需求,后续若动物还有其他行为(比如进食),也可以写在AnimalAction类中。

优化设计2

我们可以发现Move方法中,每一种动物的移动行为可能都不同,每需要一个新物种的移动行为,可能我们就会修改方法的实现代码。也就是说,不同动物的移动方法耦合在了一个Move方法中,这是否也是违背了单一职责呢?我个人理解是的。

方法级别的单一职责

保留Animal类的基本信息:

internal class Animal
{
private string name = string.Empty;

public void SetName(string name)
{
this.name = name;
}
}

将Move方法拆分成不同的方法:

public void Fly()
{
Console.WriteLine($"{name} 飞行");
}
public void Swim()
{
Console.WriteLine($"{name} 游泳");
}
public void Walk()
{
Console.WriteLine($"{name} 步行");
}

这样一来,每个方法也只负责自己的职责。

有人会觉得扯淡,确实,实际应用中可能不会这样拆分,但是此处只是用做案例来理解类和方法级别的单一职责原则。

更优的设计

保留Animal类的基本信息:

internal class Animal
{
private string name = string.Empty;

public void SetName(string name)
{
this.name = name;
}
}

将不同动物拆分成不同的类,每个类只专著自己的Move方法:

internal class Bird : Animal
{
public void Move()
{
Console.WriteLine("鸟 飞行");
}
}

internal class Fish : Animal
{
public void Move()
{
Console.WriteLine("鱼 游泳");
}
}

internal class Ant : Animal
{
public void Move()
{
Console.WriteLine("蚂蚁 步行");
}
}

这样一来,不仅遵循了单一职责原则,而且当我们遇到各种需求的变更,比如说鸟的飞行路线有变(修改Bird类的Move方法),新增乌龟“爬行”的移动方法(新增Tortoise类,实现乌龟Move方法)。不管怎么改需求,原有的Animal,Fish,Ant等类以及其中的Move方法都不需要修改。

一个类的多个动作,交给别的类去做!一个方法的多个动作,交给别的方法去做!同理,模块,程序集、应用等都可以以此来满足单一职责,增强稳定性。

优缺点

优点

1.降低复杂度。

2.提高可维护性

缺点

1.拆分多了,碎片化,不利于管理和使用。

经验心得

单一职责原则不是一时半会就能理解和运用的,其难点在于它没有一个固定的公式或者模板来告诉你什么时候应该分离成单一职责,以及分离到何种程度,设计人员不应该一昧的追求单一职责,也不应该不遵循单一职责,需要设计人员有较强的分析能力和实践经验。如果多个职责总是同时发生改变则可以将他们封装在一起。

如果一个类足够简单,可以在类的级别违背单一职责。同理如果一个方法足够简单,也可以在方法级别违背单一职责。

文章写于博主初学设计模式(准确来说是初次系统性的学习设计模式),所以对单一职责理解也是尚浅,欢迎各路大神多加指点,探讨!

版权声明:本文由不落阁原创出品,转载请注明出处!

本文链接:http://www.leo96.com/article/detail/83

广告位

来说两句吧
最新评论

暂无评论,大侠不妨来一发?