实战:面向对象综合
银行账户系统
目标: 构建一个银行账户系统,使用类、继承和多态来管理不同类型的账户。
需求:
Account基类,包含余额、存款和取款方法SavingsAccount继承Account,添加利息计算,取款时不能透支CheckingAccount继承Account,支持透支额度- 使用多态方式统一调用取款操作
示例
CSHARP
using System;
using System.Collections.Generic;
class Account
{
public string Owner { get; set; }
public decimal Balance { get; protected set; }
public Account(string owner, decimal balance)
{
Owner = owner;
Balance = balance;
}
public virtual void Deposit(decimal amount)
{
if (amount <= 0)
{
Console.WriteLine("存款金额必须大于0");
return;
}
Balance += amount;
Console.WriteLine($"{Owner} 存入 {amount:C},余额 {Balance:C}");
}
public virtual void Withdraw(decimal amount)
{
if (amount <= 0)
{
Console.WriteLine("取款金额必须大于0");
return;
}
if (amount > Balance)
{
Console.WriteLine($"{Owner} 余额不足,无法取款 {amount:C}");
return;
}
Balance -= amount;
Console.WriteLine($"{Owner} 取出 {amount:C},余额 {Balance:C}");
}
public virtual void DisplayInfo()
{
Console.WriteLine($"账户持有人:{Owner},余额:{Balance:C}");
}
}
class SavingsAccount : Account
{
public decimal InterestRate { get; set; }
public SavingsAccount(string owner, decimal balance, decimal interestRate)
: base(owner, balance)
{
InterestRate = interestRate;
}
public void ApplyInterest()
{
decimal interest = Balance * InterestRate;
Balance += interest;
Console.WriteLine($"{Owner} 获得利息 {interest:C},余额 {Balance:C}");
}
public override void Withdraw(decimal amount)
{
if (amount <= 0)
{
Console.WriteLine("取款金额必须大于0");
return;
}
if (amount > Balance)
{
Console.WriteLine($"储蓄账户不能透支,余额 {Balance:C},无法取款 {amount:C}");
return;
}
Balance -= amount;
Console.WriteLine($"{Owner}(储蓄) 取出 {amount:C},余额 {Balance:C}");
}
public override void DisplayInfo()
{
Console.WriteLine($"[储蓄账户] 持有人:{Owner},余额:{Balance:C},利率:{InterestRate:P}");
}
}
class CheckingAccount : Account
{
public decimal OverdraftLimit { get; set; }
public CheckingAccount(string owner, decimal balance, decimal overdraftLimit)
: base(owner, balance)
{
OverdraftLimit = overdraftLimit;
}
public override void Withdraw(decimal amount)
{
if (amount <= 0)
{
Console.WriteLine("取款金额必须大于0");
return;
}
if (amount > Balance + OverdraftLimit)
{
Console.WriteLine($"超过透支额度,可用 {Balance + OverdraftLimit:C},无法取款 {amount:C}");
return;
}
Balance -= amount;
Console.WriteLine($"{Owner}(支票) 取出 {amount:C},余额 {Balance:C},透支额度 {OverdraftLimit:C}");
}
public override void DisplayInfo()
{
Console.WriteLine($"[支票账户] 持有人:{Owner},余额:{Balance:C},透支额度:{OverdraftLimit:C}");
}
}
class Program
{
static void Main()
{
List<Account> accounts = new List<Account>
{
new SavingsAccount("张三", 10000m, 0.03m),
new CheckingAccount("李四", 5000m, 2000m)
};
Console.WriteLine("=== 多态取款演示 ===");
foreach (Account acc in accounts)
{
acc.Withdraw(6000m);
}
Console.WriteLine();
Console.WriteLine("=== 存款与利息 ===");
accounts[0].Deposit(2000m);
((SavingsAccount)accounts[0]).ApplyInterest();
Console.WriteLine();
Console.WriteLine("=== 账户信息 ===");
foreach (Account acc in accounts)
{
acc.DisplayInfo();
}
}
}
TEXT
=== 多态取款演示 ===
储蓄账户不能透支,余额 ¥10,000.00,无法取款 ¥6,000.00
李四(支票) 取出 ¥6,000.00,余额 ¥-1,000.00,透支额度 ¥2,000.00
=== 存款与利息 ===
张三 存入 ¥2,000.00,余额 ¥12,000.00
张三 获得利息 ¥360.00,余额 ¥12,360.00
=== 账户信息 ===
[储蓄账户] 持有人:张三,余额:¥12,360.00,利率:3.00%
[支票账户] 持有人:李四,余额:¥-1,000.00,透支额度:¥2,000.00
图形面积计算器
目标: 使用抽象类和接口,实现多种图形的面积计算,并支持按面积排序。
需求:
- 抽象类
Shape,定义抽象方法Area() Circle和Rectangle继承Shape,实现面积计算- 实现
IComparable<Shape>接口,按面积排序 - 展示多态排序效果
示例
CSHARP
using System;
using System.Collections.Generic;
abstract class Shape : IComparable<Shape>
{
public abstract double Area();
public int CompareTo(Shape other)
{
if (other == null) return 1;
return Area().CompareTo(other.Area());
}
public override string ToString()
{
return $"{GetType().Name} - 面积:{Area():F2}";
}
}
class Circle : Shape
{
public double Radius { get; set; }
public Circle(double radius)
{
Radius = radius;
}
public override double Area()
{
return Math.PI * Radius * Radius;
}
public override string ToString()
{
return $"Circle(半径={Radius}) - 面积:{Area():F2}";
}
}
class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public Rectangle(double width, double height)
{
Width = width;
Height = height;
}
public override double Area()
{
return Width * Height;
}
public override string ToString()
{
return $"Rectangle({Width}x{Height}) - 面积:{Area():F2}";
}
}
class Program
{
static void Main()
{
List<Shape> shapes = new List<Shape>
{
new Circle(5),
new Rectangle(4, 6),
new Circle(2),
new Rectangle(10, 3),
new Circle(3.5)
};
Console.WriteLine("=== 排序前 ===");
foreach (Shape s in shapes)
{
Console.WriteLine(s);
}
shapes.Sort();
Console.WriteLine();
Console.WriteLine("=== 按面积排序后 ===");
foreach (Shape s in shapes)
{
Console.WriteLine(s);
}
Console.WriteLine();
Console.WriteLine($"总面积:{TotalArea(shapes):F2}");
}
static double TotalArea(List<Shape> shapes)
{
double total = 0;
foreach (Shape s in shapes)
{
total += s.Area();
}
return total;
}
}
TEXT
=== 排序前 ===
Circle(半径=5) - 面积:78.54
Rectangle(4x6) - 面积:24.00
Circle(半径=2) - 面积:12.57
Rectangle(10x3) - 面积:30.00
Circle(半径=3.5) - 面积:38.48
=== 按面积排序后 ===
Circle(半径=2) - 面积:12.57
Rectangle(4x6) - 面积:24.00
Rectangle(10x3) - 面积:30.00
Circle(半径=3.5) - 面积:38.48
Circle(半径=5) - 面积:78.54
总面积:183.59
简单库存管理系统
目标: 使用泛型集合和事件,构建一个库存管理系统,当库存低于阈值时触发低库存事件。
需求:
Product类,包含名称、数量和价格Inventory类,使用List<Product>管理商品- 低库存事件,当商品数量低于阈值时触发通知
- 提供 Add、Remove、Search 方法
示例
CSHARP
using System;
using System.Collections.Generic;
class Product
{
public string Name { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
public int LowStockThreshold { get; set; }
public Product(string name, int quantity, decimal price, int lowStockThreshold)
{
Name = name;
Quantity = quantity;
Price = price;
LowStockThreshold = lowStockThreshold;
}
public bool IsLowStock()
{
return Quantity < LowStockThreshold;
}
public override string ToString()
{
return $"{Name} - 数量:{Quantity},单价:{Price:C},阈值:{LowStockThreshold}";
}
}
class LowStockEventArgs : EventArgs
{
public Product Product { get; set; }
public int CurrentQuantity { get; set; }
public LowStockEventArgs(Product product, int currentQuantity)
{
Product = product;
CurrentQuantity = currentQuantity;
}
}
class Inventory
{
private List<Product> products = new List<Product>();
public event EventHandler<LowStockEventArgs> LowStockAlert;
public void Add(Product product)
{
Product existing = FindByName(product.Name);
if (existing != null)
{
existing.Quantity += product.Quantity;
Console.WriteLine($"商品 {product.Name} 已存在,数量增加至 {existing.Quantity}");
}
else
{
products.Add(product);
Console.WriteLine($"添加商品:{product.Name},数量:{product.Quantity}");
}
CheckLowStock(product);
}
public void Remove(string name, int quantity)
{
Product product = FindByName(name);
if (product == null)
{
Console.WriteLine($"商品 {name} 不存在");
return;
}
if (quantity > product.Quantity)
{
Console.WriteLine($"商品 {name} 库存不足,当前数量:{product.Quantity},请求移除:{quantity}");
return;
}
product.Quantity -= quantity;
Console.WriteLine($"移除商品 {name} 数量 {quantity},剩余 {product.Quantity}");
CheckLowStock(product);
}
public Product FindByName(string name)
{
foreach (Product p in products)
{
if (p.Name == name)
{
return p;
}
}
return null;
}
public void DisplayAll()
{
Console.WriteLine("=== 库存清单 ===");
foreach (Product p in products)
{
string warning = p.IsLowStock() ? " ⚠️低库存" : "";
Console.WriteLine($"{p}{warning}");
}
Console.WriteLine($"商品种类:{products.Count}");
}
protected virtual void OnLowStock(LowStockEventArgs e)
{
LowStockAlert?.Invoke(this, e);
}
private void CheckLowStock(Product product)
{
if (product.IsLowStock())
{
OnLowStock(new LowStockEventArgs(product, product.Quantity));
}
}
}
class Program
{
static void Main()
{
Inventory inventory = new Inventory();
inventory.LowStockAlert += OnLowStock;
inventory.Add(new Product("键盘", 50, 299m, 10));
inventory.Add(new Product("鼠标", 30, 99m, 10));
inventory.Add(new Product("显示器", 5, 1999m, 10));
Console.WriteLine();
inventory.Remove("显示器", 2);
inventory.Remove("键盘", 45);
Console.WriteLine();
inventory.Add(new Product("键盘", 3, 299m, 10));
Console.WriteLine();
Product found = inventory.FindByName("鼠标");
if (found != null)
{
Console.WriteLine($"搜索结果:{found}");
}
Console.WriteLine();
inventory.DisplayAll();
}
static void OnLowStock(object sender, LowStockEventArgs e)
{
Console.WriteLine($"💡 [低库存预警] {e.Product.Name} 当前数量 {e.CurrentQuantity},低于阈值 {e.Product.LowStockThreshold}");
}
}
TEXT
添加商品:键盘,数量:50
添加商品:鼠标,数量:30
添加商品:显示器,数量:5
💡 [低库存预警] 显示器 当前数量 5,低于阈值 10
移除商品 显示器 数量 2,剩余 3
💡 [低库存预警] 显示器 当前数量 3,低于阈值 10
移除商品 键盘 数量 45,剩余 5
💡 [低库存预警] 键盘 当前数量 5,低于阈值 10
商品 键盘 已存在,数量增加至 8
💡 [低库存预警] 键盘 当前数量 8,低于阈值 10
搜索结果:鼠标 - 数量:30,单价:¥99.00,阈值:10
=== 库存清单 ===
键盘 - 数量:8,单价:¥299.00,阈值:10 ⚠️低库存
鼠标 - 数量:30,单价:¥99.00,阈值:10
显示器 - 数量:3,单价:¥1,999.00,阈值:10 ⚠️低库存
商品种类:3
❓ 常见问题
Q 储蓄账户取款时为什么不能透支?
A 储蓄账户的设计原则是保守理财,重写 Withdraw 方法时增加了余额检查,拒绝超过余额的取款请求。
Q 抽象类和接口在该选哪个?
A 如果有公共字段或默认实现,用抽象类(如 Shape 的 CompareTo);如果只定义行为契约,用接口(如 IComparable<T>)。可以同时使用两者。
Q 事件和委托有什么区别?
A 事件是委托的封装,外部只能通过 += 和 -= 订阅/取消,不能直接调用,提供了更安全的发布-订阅模式。
📖 小节
- 通过银行账户系统练习了类继承与多态,Override Withdraw 实现不同取款策略
- 通过图形面积计算器练习了抽象类与 IComparable
泛型接口的联合使用 - 通过库存管理系统练习了 List
泛型集合、自定义事件和 EventArgs 传递数据 - 三个项目综合覆盖了 Phase 3 的核心知识:继承、多态、抽象类、接口、泛型和事件
📝 作业
- 为银行账户系统添加
FixedDepositAccount类,设定固定存期,到期前取款收取违约金 - 为图形面积计算器添加
Triangle类,实现面积计算并参与排序 - 为库存管理系统添加
Purchase事件,在每次添加商品时触发,记录采购日志



