Administrator
发布于 2025-10-24 / 5 阅读
0
0

属性封装


🎯 开场导入(1分钟)

同学们好,欢迎来到不好奇课堂。

今天我们要学习项目八《面向对象编程》中的第一个子任务——属性封装。

在开始学习 “属性封装” 之前,请同学们务必先确认:你已经对项目七《面向对象基础》中的“类”和“方法”等知识点有一定的理解,甚至已经比较熟悉。如果这些内容你还没有掌握,请先复习相关知识,再继续本节的学习。因为“属性封装”正是建立在“类”和“方法”基础之上的进阶内容。

接下来,我们进入属性封装的学习。本节课的知识点有以下六点:

知识点:

  1. 封装是什么

  2. 创建一个学生类

  3. 字段存在的主要问题

  4. 如何修复字段存在的问题

  5. 为何需要属性?

  6. 声明属性的 语法

  7. 封装的定义

属性封装是什么

属性封装这个名词实际是在讲属性是什么。

属性是对字段的封装。

那封装又是什么

简单说:封就是把字段封闭起来,隐藏起来,不让外部访问,装就是把字段和方法重新组装起来,允许外部有条件的访问。

什么意思?我们先来看一个示例:

创建学生类

首先在命名空间下,我们创建一个只包含一个字段的学生类

class Student
{
    public int age;
}

然后,我们去创建两个实例对象s1和s2

static void Main()
{
    //
    Student s1 = new Student();
    Student s2 = new Student();
    //接下来为s1对象的age字段赋值200
    s1.age = 200; 
      //接下来为s2对象的age字段赋值-18
    s1.age = -18; 
    //然后再把s1和s2的age字段输出到控制台
    Console.WriteLine(s1.age);
    Console.WriteLine(s2.age); 
   //点击运行按钮,在控制台中输出了年龄200和-18.
}

字段存在的主要问题

到这里,我们就发现了字段的问题,第一个问题就是:

  1. 数据安全问题:即使一个学生的年龄被设置到了一个非常不合理的200和负数,也可以正常输出。造成这种结果的元凶就是:字段使用了public修饰符,把字段公开暴露给外部,这就等于把类的内部结构暴露给外部。这样做的结果就是:谁都可以随意改数据

  2. 再来看第2个问题:字段会造成代码的难以维护:因为字段是公开的,所以很多外部代码都直接访问它。有一天当你想修改 age时 ,却发现所有外部代码都要改,风险巨大。

如何修复字段存在的问题

修复字段存在的问题,第一步就是"封“:

  • 封就是通过把字段访问修饰符改为private,对外封闭字段,隐藏字段。这样就实现了”封“。

class Student
{
    private int age;
}

可以看到: s1.age这里已经报错,因为改为private后,字段只能在类的内部分文,无法从外部实例访问。

static void Main()
{
    Student s1 = new Student();
    s1.age = 200; //报错
​
    Student s2 = new Student();
    s1.age = -18; //报错
​
    Console.WriteLine(s1.age);//报错
    Console.WriteLine(s2.age); //报错
}

修复字段存在的问题,第二步就是装:

  • 装就是组装,组装方法和字段,通过方法把字段暴露出去。因为封装的目的不是为了“禁止外部的访问”,而是希望“控制外部的访问”,防止外部实例对象对数据随意修改。

  • 为了实现对封闭字段的控制,我们需要两个特殊的方法来组装字段:

    • Get方法:用于向外暴露字段

public int GetAge() //首先声明一个返回类型为int的GetAge方法,注意方法名字要使用帕斯卡命名法
{//在方法体内,只需简单的返回字段即可。 
  return age;
}

Set方法:用于修改字段, //接下来声明一个setAge方法,不需要返回值,在括号内传入参数newAge,在方法体内把新的值赋值给字段age

public void SetAge(string newAge)
{
     age = newAge;
}

这样通过get和set方法,我们就实现了向外暴露字段数据。

通过方法封装字段的好处是:我们随时可以在方法内部,添加对数据验证的业务逻辑。

比如:一个人的年龄,不可能是负数,也不能200岁。

所以我们在setAge方法内部添加验证:

public void SetAge(string newAge)
{
  //当年龄大于等于0或小于等于150岁时,才允许赋值
  if (newAge >= 0 && newAge <= 150)
     age = newAge;
  else//否则,我们就提示:年龄不合法
     Console.WriteLine("年龄不合法!");
}

为何还需要属性

虽然方法能实现封装,但语法太啰嗦。 要写两个方法(GetXSetX), 而实例对象上使用时还需要函数调用和参数:可读性差,不直观。

p.SetAge(30);
Console.WriteLine(p.GetAge());

属性的语法

所以 C# 引入了 属性(Property) ——

C#把get和set方法包装在了一个叫“属性访问器”的特殊结构体内,它的语法是这样的

private int age;
​
public int Age //首先,声明属性头的语法和声明字段的语法相似,但必须指定访问修饰符为public, 属性名需要使用帕斯卡命名法
{//其次,整个属性体,被称为“属性访问器”,它由get访问器和set访问器组成,
  //get访问器用于读取字段,所以,在get访问器内,需要return age; 
    get { return age; } 
  //set访问器用于修改字段,所以在set访问器内, 需要为字段age赋值,其中value这个单词是一个特殊的关键字,表示传入的新值。
    set { age = value; }
  
}
​

本质上讲,get和set访问器是get和set方法的语法糖。

p.Age = 20;

编译器会帮你调用:

p.set_Age(20);

而接受实参20的形参,其实就是关键字 value,代表“外部传入的值”。

封装下一个定义:

封装就是把数据和操作打包在一起,对外隐藏内部实现,只暴露安全、受控的接口。

用八个字概括:隐藏数据,暴露接口。


评论