在大学里学习C++的时候,老师说C++是一门面向对象的语言,面向对象的三大特征是封装、继承和多态。什么是封装呢?一般来说封装就是隐藏类的数据成员,只向外提供一些公用的操作接口,只能通过这些接口来操作类的数据成员,而不能直接对这些数据成员进行赋值改变等操作。这样做的好处是什么呢?如果选择直接暴露数据成员,有些人可能会把这些成员修改为非法数据导致程序出错。所以封装了操作数据成员的细节,能够对新值进行验证或者其他操作等。
所以一直以来我对封装的理解就是隐藏数据成员,通过接口来操作它们。
public class Person { //... private int _Age; public int Age { get { return _Age; } set { if(value >= 0) _Age = value; } } }
但是这种理解是很初级的,封装是面向对象中很重要的一环,它不仅仅表示隐藏数据成员,它还表示封装变化,有一句很有名的话:Encapsulate what varies. 它告诉我们只要是会变化的,就要封装它!用好封装这一面向对象的基本准则,能够让我们的软件系统更具有扩展能力和弹性,能更好的应付变化或者扩展的需求。因为在软件开发中,唯一不变的就是变化。
下面用例子来说明封装一切可能的变化。比如我们要写一个Person类,记录一些Person的基本信息:
public class Person { private string _FirstName; private string _LastName; private int _Age; private bool _Sex; private string _IdentityID; private float _Stature; private Country _Nationality; //... public Person(string firstName, string lastName,...) { //... } }
当然可能还有其它字段,这里也不一一列举了。但是需求是很容易改变的,可能突然有一天,客户要增加一些信息,比如就职单位,毕业学校等等。如果按照上面的设计类的改动是必不可少的,增加字段,修改构造函数,使用到Person类的地方可能都要进行修改。这时就会有人提出要对Person类进行重构,因为信息字段很容易变化,增加或者删除,所以要封装它们。
public class Person { private string _FirstName; private string _LastName; private string _IdentityID; public Person(string firstName, string lastName, string identityID, PersonInfo info) { //... } } public class PersonInfo { private int _Age; private bool _Sex; private float _Stature; private Country _Nationality; //... }
现在看来Person类和PersonInfo类进行关联,所有的个人信息都放在PersonInfo类中进行保存,如果需要增加或者删除信息字段的时候,只需要改动PersonInfo类就 可以了而不用修改Person类。不过这样做我们还是需要修改PersonInfo类,所以又有人提出另一种重构方案:
public class Person { private string _FirstName; private string _LastName; private string _IdentityID; private Hashtable _Information; public Person(string firstName, string lastName, string identityID) { //... } }
把Person的个人信息都封装在一个Hashtable中,不管这些字段是不是需要变化,代码都不需要改变。(当然这种方案也不一定是最好的,只是一种参考)
由此可以看到封装的威力,它使系统更具有弹性,当遇到变化的时候,我们可以自由应对。当然封装不仅仅用于字段,还可以用于封装行为,在《Design Patterns Explained》里面有很好的解释和示例,有时间下次再写。
这句话一定要记住:Encapsulate what varies.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?