阐明我对 C# 封装的理解
Clarifying my Understanding of Encapsulation in C#
这几天我一直在想封装,想知道我的理解是否正确。
是封装,当你创建一个class或结构时,在class或结构内部创建你不想要其他classes或结构的私有变量和方法访问,然后创建 public 方法来读取、写入或使用其他 classes 或结构中的私有变量和方法?
如果是这样,你为什么要这样做?你怎么知道什么时候用这个?与不使用封装相比,这有什么优势?如果可能,是否可以提供一些 "bad" 代码的示例,这些代码将从封装中获益?
感谢您花时间阅读我的问题。
封装用于更明确地定义class的[预期]行为。
假设你有一个 Person
class 像这样:
public class Person
{
public int Age { get; set; }
public string Name { get; set; }
}
一个 [真实] 人的年龄只会增加,所以你为什么允许任何人重新分配它?
相反,您可以封装年龄,使其必须遵循其预期行为(代价是编写更多代码来处理分配/获取值),如下所示:
public class Person
{
private int _age = 0;
public int Age { get => _age; }
public string Name { get; set; }
public void Birthday()
{
_age += 1;
}
}
这样可以保证年龄永不下降
把我的两分钱放进去。
对于封装,基本上有两个原因。
- 保护。
- 组织。
您必须意识到,您编写的代码不仅供您自己使用,还供其他人阅读和使用(他们无法更改您的代码),尤其是在您创建库或框架时。当其他人使用您的 class/library 时,他们不会想到您的 class 的所有实施细节。他们希望您的代码在直观使用时能够正常工作。
组织:
将相关信息放在正确的位置。例如在 c# List<T>
中有一个 属性 Count
,很自然地要跟踪你的列表中有多少项,用户自然会询问我的列表中有多少项。跟踪它应该是 List
class 的责任,而且更容易。如果你不提供这个 属性 怎么办?使用必须自己跟踪它。每次想知道列表中有多少项,都得自己写重复的代码和逻辑来统计。当您在 'List' 之外跟踪它时很容易出错,而当它发生在许多 places.The Count
信息自然属于您的 List
时很难进行代码更改class,自然应该留在那里。每次您想知道 Count 时,只需询问您的 List
Object.
保护:
为了保护您的对象内部状态在使用过程中始终正确。
来自 about 的相同示例。 'Count' 属性 实际上是 public 读写。
当你实现 Add
Remove
时,你会记得增加或减少 Count
,你会记得保护你的 Count
与列表中的多少项目同步并且永远不会低于0。想象一下,如果没有封装,一切都是public。没有什么能阻止用户或你自己在 10 年后做 Count = -100
(相信我,其他用户或你自己在 10 年后会这样做),然后你的 List
对象完全变成 none-感觉。并且它会产生许多难以发现的错误,甚至会造成真正的巨大损失,永远不要低估一个程序的破坏力
错误可以做到。
这几天我一直在想封装,想知道我的理解是否正确。
是封装,当你创建一个class或结构时,在class或结构内部创建你不想要其他classes或结构的私有变量和方法访问,然后创建 public 方法来读取、写入或使用其他 classes 或结构中的私有变量和方法?
如果是这样,你为什么要这样做?你怎么知道什么时候用这个?与不使用封装相比,这有什么优势?如果可能,是否可以提供一些 "bad" 代码的示例,这些代码将从封装中获益?
感谢您花时间阅读我的问题。
封装用于更明确地定义class的[预期]行为。
假设你有一个 Person
class 像这样:
public class Person
{
public int Age { get; set; }
public string Name { get; set; }
}
一个 [真实] 人的年龄只会增加,所以你为什么允许任何人重新分配它?
相反,您可以封装年龄,使其必须遵循其预期行为(代价是编写更多代码来处理分配/获取值),如下所示:
public class Person
{
private int _age = 0;
public int Age { get => _age; }
public string Name { get; set; }
public void Birthday()
{
_age += 1;
}
}
这样可以保证年龄永不下降
把我的两分钱放进去。
对于封装,基本上有两个原因。
- 保护。
- 组织。
您必须意识到,您编写的代码不仅供您自己使用,还供其他人阅读和使用(他们无法更改您的代码),尤其是在您创建库或框架时。当其他人使用您的 class/library 时,他们不会想到您的 class 的所有实施细节。他们希望您的代码在直观使用时能够正常工作。
组织:
将相关信息放在正确的位置。例如在 c# List<T>
中有一个 属性 Count
,很自然地要跟踪你的列表中有多少项,用户自然会询问我的列表中有多少项。跟踪它应该是 List
class 的责任,而且更容易。如果你不提供这个 属性 怎么办?使用必须自己跟踪它。每次想知道列表中有多少项,都得自己写重复的代码和逻辑来统计。当您在 'List' 之外跟踪它时很容易出错,而当它发生在许多 places.The Count
信息自然属于您的 List
时很难进行代码更改class,自然应该留在那里。每次您想知道 Count 时,只需询问您的 List
Object.
保护:
为了保护您的对象内部状态在使用过程中始终正确。
来自 about 的相同示例。 'Count' 属性 实际上是 public 读写。
当你实现 Add
Remove
时,你会记得增加或减少 Count
,你会记得保护你的 Count
与列表中的多少项目同步并且永远不会低于0。想象一下,如果没有封装,一切都是public。没有什么能阻止用户或你自己在 10 年后做 Count = -100
(相信我,其他用户或你自己在 10 年后会这样做),然后你的 List
对象完全变成 none-感觉。并且它会产生许多难以发现的错误,甚至会造成真正的巨大损失,永远不要低估一个程序的破坏力
错误可以做到。