🎯 开场导入(1分钟)
同学们好,欢迎来到不好奇课堂。
今天我们要学习项目八《面向对象编程》中的第一个子任务——属性封装。
在开始学习 “属性封装” 之前,请同学们务必先确认:你已经对项目七《面向对象基础》中的“类”和“方法”等知识点有一定的理解,甚至已经比较熟悉。如果这些内容你还没有掌握,请先复习相关知识,再继续本节的学习。因为“属性封装”正是建立在“类”和“方法”基础之上的进阶内容。
接下来,我们进入属性封装的学习。本节课的知识点有以下六点:
知识点:
封装是什么
创建一个学生类
字段存在的主要问题
如何修复字段存在的问题
为何需要属性?
声明属性的 语法
封装的定义
属性封装是什么
属性封装这个名词实际是在讲属性是什么。
属性是对字段的封装。
那封装又是什么
简单说:封就是把字段封闭起来,隐藏起来,不让外部访问,装就是把字段和方法重新组装起来,允许外部有条件的访问。
什么意思?我们先来看一个示例:
创建学生类
首先在命名空间下,我们创建一个只包含一个字段的学生类
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.
}字段存在的主要问题
到这里,我们就发现了字段的问题,第一个问题就是:
数据安全问题:即使一个学生的年龄被设置到了一个非常不合理的200和负数,也可以正常输出。造成这种结果的元凶就是:字段使用了public修饰符,把字段公开暴露给外部,这就等于把类的内部结构暴露给外部。这样做的结果就是:谁都可以随意改数据
再来看第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("年龄不合法!");
}为何还需要属性
虽然方法能实现封装,但语法太啰嗦。 要写两个方法(GetX、SetX), 而实例对象上使用时还需要函数调用和参数:可读性差,不直观。
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,代表“外部传入的值”。
封装下一个定义:
封装就是把数据和操作打包在一起,对外隐藏内部实现,只暴露安全、受控的接口。
用八个字概括:隐藏数据,暴露接口。