单一职责原则在 OOP 中有效吗?
Does the Single Responsibility Principle work in OOP?
我正在努力理解如何使单一职责原则与 OOP 一起工作。
如果要完全遵循这个原则,那不就剩下很多类,很多可能只有一个方法吗?
如果我们不完全按照原则来做,那么原则中的意义何在?
一个class应该处理一个主题,这是它的单一职责。 class Car
可以包含方法 startEngine()
或属性 weight
:
class Car
{
int weight;
void startEngine();
void stopEngine();
}
当然你可以再分解这个class。例如,为引擎定义一个 class:
class Engine
{
start();
stop();
}
class Car
{
Engine engine;
int weight;
}
但是您不应定义单独的classes来启动和停止引擎,例如:
class EngineStop
{
stop();
}
class EngineStart
{
start();
}
class Car
{
EngineStart engineStart;
EngineStop engineStop;
int weight;
}
原理说要尽可能合理的分解classes,达到抽象的目的。抽象得太深违反了这个原则。
这是对单一职责原则的常见误解之一,即 class 应该只有一个功能。一个class只负责一件事并不意味着一个class应该只有一个功能。单一职责原则意味着在逻辑上将您的功能分成不同的 classes 而不是混淆事物。
一个非常简单的例子是,假设您正在创建一个计算器,您可以在同一个 class 中添加纯粹用于计算器的所有功能(加、减、乘、除等)。您无需为计算器的每个功能创建单独的 class。但是,如果你想将计算结果打印到打印机,那么不要在计算器 class 中编写打印到打印机的逻辑,因为打印到打印机不是计算器 class 的责任。为打印机创建一个单独的class,并在class中编写与打印相关的逻辑。 如果您在计算器中编写打印功能 class 那么您就违反了单一职责原则。
我喜欢这样表述单一职责原则:“你写的每一件事——每个模块、class、接口或方法,都应该有 一个工作。它应该完成整个工作,只那个工作。
注意你写的这些东西有的大(模块),有的小(方法),有的介于两者之间(classes),还有一些大的东西是由小的东西组成的.
这不是问题,因为工作或职责也有各种规模,并且可以按层次分解。例如,警察部队的工作是 "protect and serve"——一项工作,分解为 "patrol the streets"、"solve crimes" 等,每个工作可以由不同的单位处理。这就需要协调(不同的工作),每个单位的工作分解为个别官员的工作等
对于每一项大工作,都有很多方法可以将其分解为更小的工作,并且每一个工作都可以通过遵循 SRP 和其他 SOLID 原则的软件设计来建模。决定如何分解问题是软件设计艺术的重要组成部分。
我倾向于将单一职责原则(以及很多经验法则、模式和模型)视为思考问题的一般方式。它旨在 指导您改进 您的代码,但不一定准确规定解决方案的外观。因为归根结底,软件设计是一个邪恶而主观的问题。
我不认为 SRP 应该总是导致一堆单一功能 classes。如果您有一些想要抽象的复杂逻辑,有时可能会发生这些情况。不过,一般来说,您应该倾向于 class 具有 高度内聚功能 的方法,其中方法:
都与相同的抽象相关
- 不要在同一个 class.
中混杂彼此不相关的功能
- 将业务逻辑之类的东西与 UI 分开,与 I/O
分开
共享共同依赖项
- 相关功能通常具有相关依赖性。
- 当我开始获得超过 7 个依赖项时,我通常会考虑拆分 class。通常有一个 class 我可以提取以将一些依赖项移动到一个更具凝聚力的单元中。
所有操作都在同一抽象级别
- 你的抽象应该是分层的;一些 classes 应该协调其他 classes 来完成工作流程。其他 classes 将处理具体的实施级细节。
- 避免编排风格 classes 进入细节。您不希望详细操作与更复杂操作的抽象并存(在同一个函数中,甚至是同一个 class)。
您实际上想要尝试尽可能多地分组功能,同时保持上述条件并牢记您的抽象的可理解性。单一职责原则的最终目标是帮助管理复杂性并使代码更易于理解。
在分解职责之前,您应该了解 class 应该做什么。正如马特在他的回答中提到的那样,它应该做那件事,而且只做那件事。以最简单的方式实施该想法,使其发挥作用。那就是你将编写的代码分解为职责的时候。
分解代码时要考虑的重要事项是确保分解后代码可读。
我引用 Robert C. Martin 的书 Clean Code:
The Single Responsibility Principle (SRP) states that a class or
module should have one, and only one, reason to change. This principle
gives us both a definition of responsibility, and a guidelines for
class size. Classes should have one responsibility—one reason to
change.
单一职责术语是由 Rober C. Martin 引入的。这一原则的主要格言是改变的理由。一个 class 或模块应该有一个,而且只有一个理由成为 changed.The 这一原则的主要好处是使 class 更健壮。对一个 class 或模块的更改不会破坏另一部分。
它防止一个对象成为上帝对象,这是反模式的一个例子。它还可以防止馄饨代码(包含许多微小的、紧密耦合的对象的源代码)。
因此,单一职责原则是 OOP 中良好源代码设计的重要组成部分。
我正在努力理解如何使单一职责原则与 OOP 一起工作。
如果要完全遵循这个原则,那不就剩下很多类,很多可能只有一个方法吗?
如果我们不完全按照原则来做,那么原则中的意义何在?
一个class应该处理一个主题,这是它的单一职责。 class Car
可以包含方法 startEngine()
或属性 weight
:
class Car
{
int weight;
void startEngine();
void stopEngine();
}
当然你可以再分解这个class。例如,为引擎定义一个 class:
class Engine
{
start();
stop();
}
class Car
{
Engine engine;
int weight;
}
但是您不应定义单独的classes来启动和停止引擎,例如:
class EngineStop
{
stop();
}
class EngineStart
{
start();
}
class Car
{
EngineStart engineStart;
EngineStop engineStop;
int weight;
}
原理说要尽可能合理的分解classes,达到抽象的目的。抽象得太深违反了这个原则。
这是对单一职责原则的常见误解之一,即 class 应该只有一个功能。一个class只负责一件事并不意味着一个class应该只有一个功能。单一职责原则意味着在逻辑上将您的功能分成不同的 classes 而不是混淆事物。
一个非常简单的例子是,假设您正在创建一个计算器,您可以在同一个 class 中添加纯粹用于计算器的所有功能(加、减、乘、除等)。您无需为计算器的每个功能创建单独的 class。但是,如果你想将计算结果打印到打印机,那么不要在计算器 class 中编写打印到打印机的逻辑,因为打印到打印机不是计算器 class 的责任。为打印机创建一个单独的class,并在class中编写与打印相关的逻辑。 如果您在计算器中编写打印功能 class 那么您就违反了单一职责原则。
我喜欢这样表述单一职责原则:“你写的每一件事——每个模块、class、接口或方法,都应该有 一个工作。它应该完成整个工作,只那个工作。
注意你写的这些东西有的大(模块),有的小(方法),有的介于两者之间(classes),还有一些大的东西是由小的东西组成的.
这不是问题,因为工作或职责也有各种规模,并且可以按层次分解。例如,警察部队的工作是 "protect and serve"——一项工作,分解为 "patrol the streets"、"solve crimes" 等,每个工作可以由不同的单位处理。这就需要协调(不同的工作),每个单位的工作分解为个别官员的工作等
对于每一项大工作,都有很多方法可以将其分解为更小的工作,并且每一个工作都可以通过遵循 SRP 和其他 SOLID 原则的软件设计来建模。决定如何分解问题是软件设计艺术的重要组成部分。
我倾向于将单一职责原则(以及很多经验法则、模式和模型)视为思考问题的一般方式。它旨在 指导您改进 您的代码,但不一定准确规定解决方案的外观。因为归根结底,软件设计是一个邪恶而主观的问题。
我不认为 SRP 应该总是导致一堆单一功能 classes。如果您有一些想要抽象的复杂逻辑,有时可能会发生这些情况。不过,一般来说,您应该倾向于 class 具有 高度内聚功能 的方法,其中方法:
都与相同的抽象相关
- 不要在同一个 class. 中混杂彼此不相关的功能
- 将业务逻辑之类的东西与 UI 分开,与 I/O 分开
共享共同依赖项
- 相关功能通常具有相关依赖性。
- 当我开始获得超过 7 个依赖项时,我通常会考虑拆分 class。通常有一个 class 我可以提取以将一些依赖项移动到一个更具凝聚力的单元中。
所有操作都在同一抽象级别
- 你的抽象应该是分层的;一些 classes 应该协调其他 classes 来完成工作流程。其他 classes 将处理具体的实施级细节。
- 避免编排风格 classes 进入细节。您不希望详细操作与更复杂操作的抽象并存(在同一个函数中,甚至是同一个 class)。
您实际上想要尝试尽可能多地分组功能,同时保持上述条件并牢记您的抽象的可理解性。单一职责原则的最终目标是帮助管理复杂性并使代码更易于理解。
在分解职责之前,您应该了解 class 应该做什么。正如马特在他的回答中提到的那样,它应该做那件事,而且只做那件事。以最简单的方式实施该想法,使其发挥作用。那就是你将编写的代码分解为职责的时候。
分解代码时要考虑的重要事项是确保分解后代码可读。
我引用 Robert C. Martin 的书 Clean Code:
The Single Responsibility Principle (SRP) states that a class or module should have one, and only one, reason to change. This principle gives us both a definition of responsibility, and a guidelines for class size. Classes should have one responsibility—one reason to change.
单一职责术语是由 Rober C. Martin 引入的。这一原则的主要格言是改变的理由。一个 class 或模块应该有一个,而且只有一个理由成为 changed.The 这一原则的主要好处是使 class 更健壮。对一个 class 或模块的更改不会破坏另一部分。
它防止一个对象成为上帝对象,这是反模式的一个例子。它还可以防止馄饨代码(包含许多微小的、紧密耦合的对象的源代码)。
因此,单一职责原则是 OOP 中良好源代码设计的重要组成部分。