一、前置基础(MVC学习前提)_核心特性_【C# OOP 入门】从生活例子看懂类、继承、多态和封装,避坑指南来了!
目录
- 一、类与对象:从 “设计图” 到 “实物” 的距离
- 二、封装:像手机一样 “藏起复杂,露出简单”
- 三、继承:“龙生龙,凤生凤” 的代码版
- 四、多态:“同一句话,不同理解” 的智慧
- 互动时间
大家好,我是老William_cl,今天咱们聊聊 C# 面向对象编程(OOP)的四大支柱 —— 类、继承、多态、封装。这玩意儿听起来抽象,但其实和咱们生活息息相关。学好它,不仅是 MVC 的基础,更是写出优雅代码的关键。
一、类与对象:从 “设计图” 到 “实物” 的距离
生活类比
你去 4S 店买车,展厅里的 “特斯拉 Model 3” 是具体的车(对象),而特斯拉工厂里的 “Model 3 设计图纸” 就是类。一张设计图可以造无数辆一模一样的车,类就是对象的 “模板”。
代码示例
// 定义一个"汽车"类(设计图)
public class Car
{// 类的属性(特征)public string Color { get; set; } // 颜色public string Brand { get; set; } // 品牌// 类的方法(行为)public void Run(){Console.WriteLine($"{Brand}汽车以100km/h行驶");}
}// 创建对象(用设计图造车)
class Program
{static void Main(string[] args){// 从Car类创建一个具体对象Car myCar = new Car();myCar.Color = "红色";myCar.Brand = "特斯拉";myCar.Run(); // 输出:特斯拉汽车以100km/h行驶}
}
常踩的坑
- 把类当对象用: 新手常直接调用Car.Run()(类名调用方法),但Run()是对象的行为,必须先new Car()创建对象才能调用。
- 属性未赋值就使用: 如果创建对象后没给Brand赋值,直接调用Run()会输出null汽车以…,记得初始化时给必要属性赋值。
二、封装:像手机一样 “藏起复杂,露出简单”
生活类比
你用手机时,不需要知道内部芯片怎么工作(隐藏细节),只需要按屏幕上的按钮(暴露接口)。这就是封装 —— 把复杂逻辑藏起来,只给外部必要的操作入口。
代码示例
public class BankAccount
{// 私有字段(隐藏起来,外部不能直接改)private decimal _balance; // 余额// 公开属性(控制外部访问)public string AccountNumber { get; } // 账号(只读,初始化后不能改)// 构造函数(初始化账号)public BankAccount(string accountNumber){AccountNumber = accountNumber;_balance = 0; // 初始余额为0}// 公开方法(存款,外部只能通过这个方法改余额)public void Deposit(decimal amount){if (amount > 0) // 校验:只能存正数{_balance += amount;}}// 公开方法(查询余额)public decimal GetBalance(){return _balance;}
}// 使用示例
var account = new BankAccount("622202123456789");
account.Deposit(1000); // 正确:通过方法存款
// account._balance = -500; // 错误:私有字段外部不能直接访问
Console.WriteLine(account.GetBalance()); // 输出:1000
常踩的坑
- 过度暴露细节: 把_balance设为public(公开),导致外部可以直接改负数,破坏了业务规则(余额不能为负)。记住:字段尽量private,通过public方法 / 属性控制访问。
- 忘记加校验逻辑: 如果Deposit方法没判断amount > 0,就可能存入负数,封装的意义就在于 “在内部做好防护”。
三、继承:“龙生龙,凤生凤” 的代码版
生活类比
猫和狗都是动物,都有 “姓名” 和 “吃饭” 的行为,但狗会 “吠叫”,猫会 “喵喵叫”。这时可以定义一个 “动物” 父类,猫和狗作为子类继承父类的共同特征,再添加自己的特有行为。
代码示例
// 父类(基类)
public class Animal
{public string Name { get; set; }// 父类的共同方法public void Eat(){Console.WriteLine($"{Name}在吃东西");}// 虚方法(允许子类重写)public virtual void MakeSound(){Console.WriteLine("动物发出声音");}
}// 子类(继承自Animal)
public class Dog : Animal
{// 重写父类的虚方法public override void MakeSound(){Console.WriteLine($"{Name}汪汪叫");}// 子类特有方法public void GuardHouse(){Console.WriteLine($"{Name}在看家");}
}// 使用示例
var dog = new Dog();
dog.Name = "旺财";
dog.Eat(); // 继承父类的方法:旺财在吃东西
dog.MakeSound(); // 重写后的方法:旺财汪汪叫
dog.GuardHouse(); // 子类特有方法:旺财在看家
常踩的坑
- 继承层次过深: 比如 “生物→动物→哺乳动物→狗→哈士奇”,层次太深会导致代码复杂,一般建议继承层次不超过 3 层。
- 滥用继承: 看到 “谁是谁的一种” 才用继承(如狗是一种动物),如果是 “谁有什么”(如狗有项圈),应该用组合(给 Dog 类加一个 Collar 属性)。
四、多态:“同一句话,不同理解” 的智慧
生活类比
同样一句 “开一下灯”,你可能按墙上的开关,而智能音箱用户会说 “小爱同学,开灯”—— 同一行为,不同实现,这就是多态。
代码示例
// 抽象父类(不能直接创建对象,只能被继承)
public abstract class Shape
{// 抽象方法(只有声明,没有实现,必须被子类重写)public abstract double GetArea();
}// 圆形(子类)
public class Circle : Shape
{public double Radius { get; set; }public override double GetArea(){return Math.PI * Radius * Radius; // 圆面积=πr²}
}// 矩形(子类)
public class Rectangle : Shape
{public double Length { get; set; }public double Width { get; set; }public override double GetArea(){return Length * Width; // 矩形面积=长×宽}
}// 使用示例
class Program
{static void Main(string[] args){// 多态核心:父类引用指向子类对象Shape circle = new Circle { Radius = 2 };Shape rectangle = new Rectangle { Length = 3, Width = 4 };// 同样调用GetArea(),执行不同实现Console.WriteLine($"圆面积:{circle.GetArea():F2}"); // 输出:12.57Console.WriteLine($"矩形面积:{rectangle.GetArea()}"); // 输出:12}
}
常踩的坑
- 忘记加 override: 子类重写父类方法时,如果漏写override,会变成 “方法隐藏”(用new关键字),导致多态失效(调用时会执行父类方法)。
- 抽象类实例化: 抽象类(带abstract)不能直接new Shape(),必须通过子类实例化,否则编译报错。
互动时间
OOP 的核心就是 “像现实世界一样组织代码”—— 用类描述事物,用封装保护数据,用继承复用代码,用多态灵活扩展。
你在学习 OOP 时遇到过哪些坑?或者有更生动的生活类比?欢迎在评论区留言,咱们一起交流~下一期咱们聊聊 LINQ,不见不散!