策略模式
本课属于 Coddy C# 学习旅程的“面向对象编程”单元。第 55 课,共 70 课。
策略模式是一种行为型模式,它让你可以定义一组算法,将每种算法封装在自己的类中,并在运行时互换使用。你无需将行为硬编码,而是将所需的策略注入对象。
这个模式由三部分组成:定义算法契约的策略接口、实现不同行为的具体策略类,以及使用策略的上下文类:
public interface IPaymentStrategy
{
void Pay(decimal amount);
}
public class CreditCardPayment : IPaymentStrategy
{
public void Pay(decimal amount) =>
Console.WriteLine($"Paid {amount} via Credit Card");
}
public class PayPalPayment : IPaymentStrategy
{
public void Pay(decimal amount) =>
Console.WriteLine($"Paid {amount} via PayPal");
}
public class ShoppingCart
{
private IPaymentStrategy _paymentStrategy;
public void SetPaymentMethod(IPaymentStrategy strategy)
{
_paymentStrategy = strategy;
}
public void Checkout(decimal total)
{
_paymentStrategy.Pay(total);
}
}上下文(ShoppingCart)不知道自己使用的是哪种支付方式,它只会对传入的策略调用 Pay():
var cart = new ShoppingCart();
cart.SetPaymentMethod(new CreditCardPayment());
cart.Checkout(99.99m); // 通过信用卡支付了 99.99
cart.SetPaymentMethod(new PayPalPayment());
cart.Checkout(49.99m); // 通过 PayPal 支付了 49.99策略模式可以消除复杂的条件逻辑。添加新的支付方式,只需创建一个实现 IPaymentStrategy 的新类,无需修改 ShoppingCart。这样,你的代码就可以扩展,但无需修改。
挑战
简单我们来使用策略模式构建一个运费计算器。不同的配送方式有不同的定价算法,你的系统应该能够在运行时切换算法,而不改变核心订单处理逻辑。
你需要将代码组织到三个文件中:
ShippingStrategy.cs:在Shipping命名空间中定义一个IShippingStrategy接口,其中包含一个方法CalculateCost(double weight),该方法返回一个double。然后创建三个具体的策略类:StandardShipping:按weight * 1.5计算费用ExpressShipping:按weight * 3.0 + 5.0计算费用(包含固定的快递费用)OvernightShipping:按weight * 5.0 + 10.0计算费用(高级服务,基础费用更高)
OrderProcessor.cs:在同一命名空间中创建一个OrderProcessor类。它是使用配送策略的上下文类,其中应包含:- 一个用于保存当前
IShippingStrategy的私有字段 - 一个用于更改配送策略的
SetShippingMethod(IShippingStrategy strategy)方法 - 一个
ProcessOrder(double weight)方法,该方法使用当前策略计算并返回运费
- 一个用于保存当前
Program.cs:创建一个OrderProcessor,并演示如何在运行时切换配送策略,从而将所有内容整合起来。同一个处理器只需更改策略,就能使用不同的算法计算费用。
你将收到两个输入:
- 配送方式类型:
standard、express或overnight - 包裹重量,以小数表示(例如,
4.5)
创建一个 OrderProcessor,根据输入类型设置相应的配送策略,然后处理订单并打印计算出的费用。
例如,如果输入是 express 和 4.5,输出应为:
18.5这展示了策略模式的强大之处:你的 OrderProcessor 本身不包含任何运费计算逻辑。它只会将计算委托给指定的策略,因此你可以轻松添加新的配送方式(例如 DroneDelivery),而完全不必修改处理器!
亲手试试
using System;
using Shipping;
class Program
{
public static void Main(string[] args)
{
// 读取输入
string shippingType = Console.ReadLine();
double weight = Convert.ToDouble(Console.ReadLine());
// TODO: 创建一个 OrderProcessor 实例
// TODO: 根据 shippingType("standard"、"express" 或 "overnight"),
// 创建对应的配送策略,并将其设置到处理器上
// TODO: 处理订单并打印计算出的费用
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: C# 在线编译器