在面向对象编程(OOP)中,封装、继承、多态是三大核心特性,它们共同构建了代码的模块化、复用性和灵活性。以下是对这三个概念的详细解析,结合 C# 语言特性和实际代码示例:
一、封装(Encapsulation)
定义
将数据(字段)和操作数据的方法(函数)绑定在一个单元(类)中,通过访问修饰符控制外部对内部实现的访问权限。
核心目标
- 隐藏实现细节:只暴露必要的接口(如属性、方法),保护数据完整性。
- 降低耦合度:通过接口而非实现进行交互,增强代码可维护性。
C# 实现方式
-
访问修饰符:
private
:仅类内部访问。
protected
:类内部和派生类访问。
public
:无限制访问。
internal
:同一程序集内访问。
-
属性(Property):
通过 get
/set
方法控制字段访问逻辑。
public class BankAccount {
private decimal _balance; // 私有字段,隐藏实现
public decimal Balance {
get { return _balance; }
private set { // 仅类内可修改
if (value >= 0) _balance = value;
}
}
public void Deposit(decimal amount) {
if (amount > 0) Balance += amount;
}
}
-
方法封装:
将复杂操作封装为方法,隐藏细节。
public class DataProcessor {
public void ProcessData(string input) {
ValidateInput(input); // 内部方法隐藏验证细节
// 处理逻辑...
}
private void ValidateInput(string input) {
if (string.IsNullOrEmpty(input)) throw new ArgumentException();
}
}
二、继承(Inheritance)
定义
一个类(派生类)基于另一个类(基类)扩展功能,继承其字段、属性和方法,实现代码复用。
核心目标
- 代码复用:避免重复编写公共逻辑。
- 层次化抽象:通过基类定义通用行为,派生类实现具体差异。
C# 实现方式
-
基类与派生类:
public class Animal { // 基类
public string Name { get; set; }
public virtual void Speak() => Console.WriteLine("Animal sound");
}
public class Dog : Animal { // 派生类
public override void Speak() => Console.WriteLine("Woof!");
}
public class Cat : Animal {
public override void Speak() => Console.WriteLine("Meow!");
}
-
sealed
关键字:
阻止类被继承(如 string
类)。
public sealed class Singleton { /* ... */ }
-
基类构造函数调用:
使用 base
调用基类构造函数。
public class Vehicle {
public Vehicle(int wheels) => Wheels = wheels;
public int Wheels { get; }
}
public class Car : Vehicle {
public Car() : base(4) { } // 调用基类构造函数
}
三、多态(Polymorphism)
定义
同一操作作用于不同对象时,表现出不同行为。多态分为 编译时多态(静态)和 运行时多态(动态)。
核心目标
- 接口统一化:通过抽象接口操作多种类型。
- 动态行为绑定:程序运行时决定调用哪个方法。
C# 实现方式
-
方法重写(override
):
基类方法标记为 virtual
,派生类使用 override
重写。
Animal myDog = new Dog();
myDog.Speak(); // 输出 "Woof!"(运行时多态)
-
抽象类(abstract
):
定义抽象方法强制派生类实现。
public abstract class Shape {
public abstract double Area(); // 抽象方法
}
public class Circle : Shape {
public double Radius { get; set; }
public override double Area() => Math.PI * Radius * Radius;
}
-
接口(interface
):
完全抽象的契约,支持多重继承。
public interface IDrawable {
void Draw();
}
public class Circle : IDrawable {
public void Draw() => Console.WriteLine("Drawing a circle");
}
-
方法重载(Overload):
同一类中方法名相同,参数不同(编译时多态)。
public class Calculator {
public int Add(int a, int b) => a + b;
public double Add(double a, double b) => a + b; // 重载
}
四、三者关系与设计原则
概念 | 作用 | 设计原则 |
封装 |
隐藏复杂性,保护数据 |
单一职责原则(SRP) |
继承 |
复用代码,建立层次关系 |
里氏替换原则(LSP) |
多态 |
统一接口,灵活扩展 |
开闭原则(OCP)、依赖倒置原则(DIP) |
示例:三者结合应用
// 封装:隐藏车辆内部状态
public abstract class Vehicle {
private int _speed; // 私有字段
public int Speed {
get => _speed;
set => _speed = value >= 0 ? value : 0;
}
public abstract void Move(); // 多态:抽象方法
}
// 继承:复用基类属性
public class Car : Vehicle {
public override void Move() => Console.WriteLine("Car is driving.");
}
public class Boat : Vehicle {
public override void Move() => Console.WriteLine("Boat is sailing.");
}
// 多态:通过基类引用调用不同实现
Vehicle[] vehicles = { new Car(), new Boat() };
foreach (var v in vehicles) {
v.Move(); // 输出不同行为
}
五、常见误区与最佳实践
-
避免过度继承:
- 优先使用组合(Composition)而非继承(“组合优于继承”原则)。
- 示例:用接口定义行为,类实现多个接口。
public interface IFlyable { void Fly(); }
public interface ISwimable { void Swim(); }
public class Duck : IFlyable, ISwimable {
public void Fly() => Console.WriteLine("Flying");
public void Swim() => Console.WriteLine("Swimming");
}
-
谨慎使用 protected
:
protected
字段可能破坏派生类的封装性,优先使用属性。
-
多态与性能:
- 虚方法调用有轻微性能开销,高频调用场景可考虑
sealed
类或非虚方法。
六、总结
- 封装是基础,通过访问控制保护数据。
- 继承实现代码复用,但需谨慎设计层次结构。
- 多态通过统一接口提升扩展性,结合接口和抽象类使用。
- 三者协同构建高内聚、低耦合的系统,遵循 SOLID 原则以提升代码质量。