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

什么是单一职责原则

一个类只负责一件事情
一个模块的所有功能都应该高度相关、围绕同一职责
当需求变更时,应只影响到一个类,而不是同时影响多个不相关功能的类

为什么要遵守SRP

  1. 降低耦合

当一个类承担多种职责时,一个职责的变化可能会影响到其他职责。

  1. 提高可维护性

变更影响面更小,维护更轻松。

  1. 提高可测试性

单一职责的类更容易编写单元测试。

  1. 增强可读性

结构更清晰,让别人一眼就知道这个类的目的。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class TelPhone
{
public void Dial(string phoneNumber)
{
Console.WriteLine("给 " + phoneNumber+" 打电话");
}

public void HangUp(string phoneNumber)
{
Console.WriteLine("挂断 " + phoneNumber+" 的电话");
}

public void SendMessage(string phoneNumber, string message)
{
Console.WriteLine("给 " + phoneNumber + " 发送消息: " + message);
}

public void ReceiveMessage(string phoneNumber, string message)
{
Console.WriteLine(phoneNumber + " 收到消息: " + message);
}
}

变化一:内部的变化,如果TelPhone内部的方法,任意之一,发生了改变,那会需要修改TelPhone,不符合单一职责原则
变化二:外部的变化,如果TelPhone要添加新的方法,也需要修改TelPhone

只有添加的时候才会触发这个类的改变,其他的修改都不要触发这个类的改变

优化:

给每个方法,都提炼成一个接口,抽象成一种能力,然后分别鞋类,去实现接口,最终在TelPhone中,只进行调用。

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
public interface  IDidl
{
void Dial(string phoneNumber);
}

public interface IHangUp
{
void HangUp(string phoneNumber);
}

public interface ISendMessage
{
void SendMessage(string phoneNumber, string message);
}

public interface IReceiveMessage
{
void ReceiveMessage(string phoneNumber, string message);
}

public class Dialclass : IDidl
{
public void Dial(string phoneNumber)
{
Console.WriteLine("给 " + phoneNumber + " 打电话");
}
}
public class HangUpclass : IHangUp
{
public void HangUp(string phoneNumber)
{
Console.WriteLine("挂断 " + phoneNumber + " 的电话");
}
}
public class SendMessageclass : ISendMessage
{
public void SendMessage(string phoneNumber, string message)
{
Console.WriteLine("给 " + phoneNumber + " 发送消息: " + message);
}
}
public class ReceiveMessageclass : IReceiveMessage
{
public void ReceiveMessage(string phoneNumber, string message)
{
Console.WriteLine(phoneNumber + " 收到消息: " + message);
}
}

public class TelPhone
{
private IDidl _dial;
private IHangUp _hangUp;
private ISendMessage _sendMessage;
private IReceiveMessage _receiveMessage;

public TelPhone(IDidl dial, IHangUp hangUp, ISendMessage sendMessage, IReceiveMessage receiveMessage)
{
_dial = dial;
_hangUp = hangUp;
_sendMessage = sendMessage;
_receiveMessage = receiveMessage;
}
public void Dial(string phoneNumber)
{
_dial.Dial(phoneNumber);
}

public void HangUp(string phoneNumber)
{
_hangUp.HangUp(phoneNumber);
}

public void SendMessage(string phoneNumber, string message)
{
_sendMessage.SendMessage(phoneNumber, message);
}

public void ReceiveMessage(string phoneNumber, string message)
{
_receiveMessage.ReceiveMessage(phoneNumber, message);
}
}

开放封闭原则

什么是开放封闭原则

当需求变更时,应该 通过扩展新代码 来应对
而不是修改已稳定上线的旧代码

为什么需要 OCP

  1. 减少风险

改旧代码容易引入 Bug。扩展新代码更安全。

  1. 提高可维护性

避免在核心流程中不停加 if-else、switch-case。

  1. 提高可扩展性

新增需求只需要新增类或策略,而不是动旧逻辑。

示例:

对象1:用户:属性:记录不同类型的用户(存钱、取钱、转账)
对象2:银行柜员:帮助我们用户处理不同的需求
对象3:银行业务系统:处理存钱、取钱、转账等需求的操作系统

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class Bank
{
public static void Bankclas(string[] args)
{
BankClient client = new BankClient();
client.BankType = "存款";
BankStuff stuff = new BankStuff(new BankProcess());
stuff.HandleProcess(client);
}
}

public class BankClient
{
public string? BankType{get;set;}
}

public class BankStuff
{
private BankProcess _bankProcess;
public BankStuff(BankProcess bankProcess)
{
_bankProcess = bankProcess;
}
public void HandleProcess(BankClient client)
{
switch (client.BankType)
{
case "存款":
_bankProcess.Deposit();
break;
case "取款":
_bankProcess.Withdraw();
break;
case "转账":
_bankProcess.Transfer();
break;
default:
Console.WriteLine("无效的操作");
break;
}
}
}

public class BankProcess
{
//存款
public void Deposit()
{
Console.WriteLine("存款");
}
//取款
public void Withdraw()
{
Console.WriteLine("取款");
}
//转账
public void Transfer()
{
Console.WriteLine("转账");
}
}

此代码并没有实现单一原则,且开放封闭原则,只开放并没有封闭(一个软件实体应该对扩展开放,对修改封闭。即软件实体应尽量在不修改原有代码的情况下进行扩展)

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
public class Bank
{
public static void Bankclas(string[] args)
{
IBankClient client = new TransferClient();
BankStuff ctx = new BankStuff();
ctx.HandleProcess(client);
}
}

public class BankClient
{
public string? BankType{get;set;}
}

public class BankStuff
{
private IBankProcess? _bankprocess;

public void HandleProcess(IBankClient client)
{
_bankprocess = client.GetBankProcess();
_bankprocess.BankProcess();
}
}

// 以上是Bank.cs的接口定义,下面是BankClient.cs的实现
public interface IBankClient
{
IBankProcess GetBankProcess();
}

public class DepositClient : IBankClient
{
public IBankProcess GetBankProcess()
{
return new Deposit();
}
}

public class WithdrawClient : IBankClient
{
public IBankProcess GetBankProcess()
{
return new Withdraw();
}
}

public class TransferClient : IBankClient
{
public IBankProcess GetBankProcess()
{
return new Transfer();
}
}

// 以上是Bank.cs的实现,下面是BankClient.cs的实现

public interface IBankProcess
{
void BankProcess();
}

public class Deposit : IBankProcess
{
public void BankProcess()
{
Console.WriteLine("存款");
}
}

public class Withdraw : IBankProcess
{
public void BankProcess()
{
Console.WriteLine("取款");
}
}

public class Transfer : IBankProcess
{
public void BankProcess()
{
Console.WriteLine("转账");
}
}