C# 面向对象编程实例演示
一、基础概念回顾
面向对象编程(OOP)的四大基本特性:
- 封装 - 将数据和操作数据的方法绑定在一起
- 继承 - 创建新类时重用现有类的属性和方法
- 多态 - 同一操作作用于不同对象产生不同结果
- 抽象 - 简化复杂系统,只暴露必要接口
二、完整实例演示
示例1:银行账户系统
cs
using System;
// 抽象基类 - 封装共同属性和行为
public abstract class BankAccount
{
// 封装字段
private string _accountNumber;
private decimal _balance;
// 属性 - 控制对字段的访问
public string AccountNumber
{
get => _accountNumber;
private set => _accountNumber = value;
}
public decimal Balance
{
get => _balance;
protected set => _balance = value;
}
// 构造函数
protected BankAccount(string accountNumber, decimal initialBalance)
{
AccountNumber = accountNumber;
Balance = initialBalance;
}
// 抽象方法 - 由子类实现
public abstract void Deposit(decimal amount);
public abstract void Withdraw(decimal amount);
// 虚方法 - 可被子类重写
public virtual void DisplayAccountInfo()
{
Console.WriteLine($"账户号: {AccountNumber}");
Console.WriteLine($"余额: {Balance:C}");
}
}
// 派生类 - 继承并扩展功能
public class SavingsAccount : BankAccount
{
private const decimal MinimumBalance = 100;
private const decimal InterestRate = 0.02m;
public SavingsAccount(string accountNumber, decimal initialBalance)
: base(accountNumber, initialBalance)
{
if (initialBalance < MinimumBalance)
throw new ArgumentException("储蓄账户最低余额为100元");
}
// 实现抽象方法
public override void Deposit(decimal amount)
{
if (amount <= 0)
throw new ArgumentException("存款金额必须大于0");
Balance += amount;
Console.WriteLine($"成功存入 {amount:C},当前余额: {Balance:C}");
}
public override void Withdraw(decimal amount)
{
if (amount <= 0)
throw new ArgumentException("取款金额必须大于0");
if (Balance - amount < MinimumBalance)
throw new InvalidOperationException("取款后余额不能低于最低限额");
Balance -= amount;
Console.WriteLine($"成功取出 {amount:C},当前余额: {Balance:C}");
}
// 新增方法
public void ApplyInterest()
{
decimal interest = Balance * InterestRate;
Balance += interest;
Console.WriteLine($"利息已应用: {interest:C},新余额: {Balance:C}");
}
// 重写虚方法
public override void DisplayAccountInfo()
{
base.DisplayAccountInfo();
Console.WriteLine($"账户类型: 储蓄账户");
Console.WriteLine($"最低余额要求: {MinimumBalance:C}");
}
}
// 另一个派生类
public class CheckingAccount : BankAccount
{
private const decimal OverdraftLimit = -500;
public CheckingAccount(string accountNumber, decimal initialBalance)
: base(accountNumber, initialBalance)
{
}
public override void Deposit(decimal amount)
{
if (amount <= 0)
throw new ArgumentException("存款金额必须大于0");
Balance += amount;
Console.WriteLine($"支票账户存入 {amount:C},当前余额: {Balance:C}");
}
public override void Withdraw(decimal amount)
{
if (amount <= 0)
throw new ArgumentException("取款金额必须大于0");
if (Balance - amount < OverdraftLimit)
throw new InvalidOperationException($"取款后余额不能低于透支限额 {OverdraftLimit:C}");
Balance -= amount;
Console.WriteLine($"支票账户取出 {amount:C},当前余额: {Balance:C}");
}
public void WriteCheck(decimal amount)
{
try
{
Withdraw(amount);
Console.WriteLine($"已开具 {amount:C} 支票");
}
catch (Exception ex)
{
Console.WriteLine($"开具支票失败: {ex.Message}");
}
}
}
// 演示类
public class BankDemo
{
public static void Main()
{
// 多态 - 使用基类引用指向派生类对象
BankAccount savings = new SavingsAccount("SAV12345", 1000);
BankAccount checking = new CheckingAccount("CHK67890", 500);
// 调用方法
savings.Deposit(200);
savings.Withdraw(50);
savings.DisplayAccountInfo();
Console.WriteLine("\n-----------------\n");
checking.Deposit(300);
checking.WriteCheck(100);
checking.Withdraw(700); // 尝试透支
checking.DisplayAccountInfo();
// 使用is和as运算符
if (savings is SavingsAccount savingsAcc)
{
savingsAcc.ApplyInterest();
}
BankAccount? unknownAccount = null;
var tempAccount = unknownAccount as SavingsAccount;
if (tempAccount == null)
{
Console.WriteLine("账户类型转换失败");
}
}
}
示例2:图形计算系统
cs
using System;
using System.Collections.Generic;
// 接口定义
public interface IShape
{
decimal CalculateArea();
decimal CalculatePerimeter();
void Draw();
}
// 具体实现类
public class Circle : IShape
{
private decimal _radius;
public Circle(decimal radius)
{
if (radius <= 0)
throw new ArgumentException("半径必须大于0");
_radius = radius;
}
public decimal Radius => _radius;
public decimal CalculateArea() => (decimal)Math.PI * _radius * _radius;
public decimal CalculatePerimeter() => 2 * (decimal)Math.PI * _radius;
public void Draw()
{
Console.WriteLine($"绘制圆形,半径: {_radius}");
// 实际绘图代码...
}
}
public class Rectangle : IShape
{
private decimal _width;
private decimal _height;
public Rectangle(decimal width, decimal height)
{
if (width <= 0 || height <= 0)
throw new ArgumentException("宽度和高度必须大于0");
_width = width;
_height = height;
}
public decimal Width => _width;
public decimal Height => _height;
public decimal CalculateArea() => _width * _height;
public decimal CalculatePerimeter() => 2 * (_width + _height);
public void Draw()
{
Console.WriteLine($"绘制矩形,宽度: {_width},高度: {_height}");
// 实际绘图代码...
}
}
// 工厂类 - 封装对象创建逻辑
public static class ShapeFactory
{
public static IShape CreateShape(string shapeType, params decimal[] parameters)
{
return shapeType.ToLower() switch
{
"circle" => new Circle(parameters[0]),
"rectangle" => new Rectangle(parameters[0], parameters[1]),
_ => throw new ArgumentException("未知的形状类型")
};
}
}
// 图形管理器 - 组合多个图形
public class ShapeManager
{
private readonly List<IShape> _shapes = new();
public void AddShape(IShape shape)
{
_shapes.Add(shape);
}
public decimal TotalArea() => _shapes.Sum(s => s.CalculateArea());
public decimal TotalPerimeter() => _shapes.Sum(s => s.CalculatePerimeter());
public void DrawAllShapes()
{
foreach (var shape in _shapes)
{
shape.Draw();
}
}
}
// 演示类
public class ShapeDemo
{
public static void Main()
{
// 多态使用
IShape circle = new Circle(5);
IShape rectangle = new Rectangle(4, 6);
Console.WriteLine($"圆形面积: {circle.CalculateArea()}");
Console.WriteLine($"矩形周长: {rectangle.CalculatePerimeter()}");
// 工厂模式使用
IShape anotherCircle = ShapeFactory.CreateShape("circle", 3);
IShape anotherRectangle = ShapeFactory.CreateShape("rectangle", 2, 5);
// 组合模式使用
var manager = new ShapeManager();
manager.AddShape(circle);
manager.AddShape(rectangle);
manager.AddShape(anotherCircle);
manager.AddShape(anotherRectangle);
Console.WriteLine($"\n所有图形总面积: {manager.TotalArea()}");
Console.WriteLine($"所有图形总周长: {manager.TotalPerimeter()}");
Console.WriteLine("\n绘制所有图形:");
manager.DrawAllShapes();
// 接口实现检查
if (circle is Circle c)
{
Console.WriteLine($"这是一个圆形,半径: {c.Radius}");
}
// 使用as运算符
var maybeCircle = rectangle as Circle;
if (maybeCircle == null)
{
Console.WriteLine("这不是一个圆形");
}
}
}
示例3:动物模拟系统
cs
using System;
// 基类
public abstract class Animal
{
// 字段封装
private string _name;
private int _age;
// 属性
public string Name
{
get => _name;
set => _name = value ?? throw new ArgumentNullException(nameof(value));
}
public int Age
{
get => _age;
protected set => _age = value >= 0 ? value : throw new ArgumentOutOfRangeException(nameof(value));
}
// 构造函数
protected Animal(string name, int age)
{
Name = name;
Age = age;
}
// 抽象方法 - 必须由子类实现
public abstract void MakeSound();
// 虚方法 - 可被子类重写
public virtual void Eat()
{
Console.WriteLine($"{Name}正在吃东西");
}
// 密封方法 - 阻止进一步重写
public sealed override string ToString()
{
return $"{GetType().Name}: {Name}, {Age}岁";
}
}
// 派生类
public class Dog : Animal
{
public Dog(string name, int age) : base(name, age)
{
}
public override void MakeSound()
{
Console.WriteLine($"{Name}汪汪叫!");
}
// 新增方法
public void Fetch()
{
Console.WriteLine($"{Name}正在捡球");
}
}
public class Cat : Animal
{
public Cat(string name, int age) : base(name, age)
{
}
public override void MakeSound()
{
Console.WriteLine($"{Name}喵喵叫!");
}
// 重写基类方法
public override void Eat()
{
Console.WriteLine($"{Name}正在优雅地吃猫粮");
}
// 隐藏基类方法(不推荐)
public new void ToString()
{
Console.WriteLine("这不会覆盖基类的ToString");
}
}
// 接口
public interface ITrainable
{
void Train(string command);
}
// 实现接口的类
public class PoliceDog : Dog, ITrainable
{
public PoliceDog(string name, int age) : base(name, age)
{
}
public void Train(string command)
{
Console.WriteLine($"{Name}正在接受'{command}'训练");
}
}
// 演示类
public class AnimalDemo
{
public static void Main()
{
// 多态使用
Animal[] animals = new Animal[]
{
new Dog("旺财", 3),
new Cat("咪咪", 2),
new PoliceDog("阿黄", 5)
};
foreach (var animal in animals)
{
animal.MakeSound();
animal.Eat();
// 类型检查与转换
if (animal is Dog dog)
{
dog.Fetch();
}
if (animal is ITrainable trainable)
{
trainable.Train("坐下");
}
Console.WriteLine(animal.ToString());
Console.WriteLine();
}
// 接口实现检查
if (animals[2] is PoliceDog policeDog)
{
policeDog.Train("卧倒");
}
// as运算符
var maybeTrainable = animals[1] as ITrainable;
if (maybeTrainable == null)
{
Console.WriteLine("猫不能接受训练");
}
}
}
三、关键概念详解
1. 封装
优点:
- 隐藏实现细节
- 提供公共接口
- 控制对数据的访问
示例:
cs
public class Person
{
// 私有字段
private string _ssn;
// 公共属性 - 控制访问
public string SSN
{
get => _ssn;
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("SSN不能为空");
if (value.Length != 9)
throw new ArgumentException("SSN必须是9位");
_ssn = value;
}
}
// 只读属性
public int Age { get; private set; }
// 构造函数初始化
public Person(string ssn, int age)
{
SSN = ssn;
Age = age;
}
// 方法封装行为
public void HaveBirthday()
{
Age++;
Console.WriteLine($"生日快乐!现在是{Age}岁");
}
}
2. 继承
语法:
cs
public class BaseClass
{
// 基类成员
}
public class DerivedClass : BaseClass
{
// 派生类成员
}
示例:
cs
public class Vehicle
{
public string Make { get; set; }
public string Model { get; set; }
public virtual void Start()
{
Console.WriteLine("车辆启动");
}
}
public class Car : Vehicle
{
public int DoorCount { get; set; }
public override void Start()
{
Console.WriteLine("汽车启动");
base.Start(); // 调用基类方法
}
public void Honk()
{
Console.WriteLine("喇叭响");
}
}
3. 多态
实现方式:
- 方法重写(override)
- 接口实现
- 抽象方法
示例:
cs
public interface IShape
{
decimal Area();
}
public class Circle : IShape
{
public decimal Radius { get; set; }
public decimal Area() => (decimal)Math.PI * Radius * Radius;
}
public class Rectangle : IShape
{
public decimal Width { get; set; }
public decimal Height { get; set; }
public decimal Area() => Width * Height;
}
// 使用
IShape[] shapes = new IShape[]
{
new Circle { Radius = 5 },
new Rectangle { Width = 4, Height = 6 }
};
foreach (var shape in shapes)
{
Console.WriteLine($"面积: {shape.Area()}");
}
4. 抽象
抽象类:
cs
public abstract class Animal
{
public abstract void MakeSound(); // 必须由子类实现
public virtual void Eat() // 可选实现
{
Console.WriteLine("动物在吃东西");
}
}
接口:
cs
public interface IDriveable
{
void Drive();
int MaxSpeed { get; set; }
}
示例:
cs
public abstract class Shape
{
public abstract decimal CalculateArea();
public virtual void Display()
{
Console.WriteLine("这是一个形状");
}
}
public class Triangle : Shape
{
public decimal Base { get; set; }
public decimal Height { get; set; }
public override decimal CalculateArea()
{
return Base * Height / 2;
}
public new void Display() // 隐藏基类方法(不推荐)
{
Console.WriteLine("这是一个三角形");
}
}
四、设计模式示例
1. 工厂模式
cs
public interface IWeapon
{
void Attack();
}
public class Sword : IWeapon
{
public void Attack() => Console.WriteLine("挥剑攻击");
}
public class Bow : IWeapon
{
public void Attack() => Console.WriteLine("拉弓射箭");
}
public static class WeaponFactory
{
public static IWeapon CreateWeapon(string weaponType)
{
return weaponType.ToLower() switch
{
"sword" => new Sword(),
"bow" => new Bow(),
_ => throw new ArgumentException("未知武器类型")
};
}
}
// 使用
IWeapon weapon = WeaponFactory.CreateWeapon("sword");
weapon.Attack();
2. 单例模式
cs
public sealed class Logger
{
private static readonly Lazy<Logger> _instance =
new Lazy<Logger>(() => new Logger());
public static Logger Instance => _instance.Value;
private Logger() { }
public void Log(string message)
{
Console.WriteLine($"[{DateTime.Now}] {message}");
}
}
// 使用
Logger.Instance.Log("系统启动");
3. 观察者模式
cs
public interface IObserver
{
void Update(string message);
}
public class NewsAgency
{
private readonly List<IObserver> _observers = new();
public void AddObserver(IObserver observer)
{
_observers.Add(observer);
}
public void RemoveObserver(IObserver observer)
{
_observers.Remove(observer);
}
public void PublishNews(string news)
{
foreach (var observer in _observers)
{
observer.Update(news);
}
}
}
public class Subscriber : IObserver
{
public string Name { get; }
public Subscriber(string name)
{
Name = name;
}
public void Update(string message)
{
Console.WriteLine($"{Name}收到新闻: {message}");
}
}
// 使用
var agency = new NewsAgency();
agency.AddObserver(new Subscriber("张三"));
agency.AddObserver(new Subscriber("李四"));
agency.PublishNews("股市今日大涨");
五、最佳实践
-
优先使用组合而非继承:
cs// 更好的设计 - 使用组合 public class Engine { } public class Car { public Engine Engine { get; } = new Engine(); }
-
遵循SOLID原则:
- 单一职责原则(SRP)
- 开闭原则(OCP)
- 里氏替换原则(LSP)
- 接口隔离原则(ISP)
- 依赖倒置原则(DIP)
-
合理使用访问修饰符:
cspublic class MyClass { public int PublicField; // 慎用 protected int ProtectedField; internal int InternalField; protected internal int ProtectedInternalField; private int _privateField; // 推荐 }
-
避免过度使用继承:
- 继承层次不要太深(通常不超过3层)
- 考虑使用接口或组合替代
-
使用属性而非公共字段:
cs// 不推荐 public class BadDesign { public int Value; } // 推荐 public class GoodDesign { private int _value; public int Value { get => _value; set => _value = value > 0 ? value : throw new ArgumentOutOfRangeException(); } }
-
实现IDisposable接口管理资源:
cspublic class ResourceHolder : IDisposable { private bool _disposed = false; private FileStream _fileStream; public ResourceHolder(string path) { _fileStream = new FileStream(path, FileMode.Open); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { _fileStream?.Dispose(); } _disposed = true; } } ~ResourceHolder() => Dispose(false); }
通过以上实例和最佳实践,您可以更好地理解和应用C#的面向对象编程特性,编写出更健壮、可维护和可扩展的代码。