目录
[生活中的比喻:支付方式 💳](#生活中的比喻:支付方式 💳)
[7. 策略模式的优点和缺点](#7. 策略模式的优点和缺点)
[✅ 优点:](#✅ 优点:)
[❌ 缺点:](#❌ 缺点:)
[策略模式 vs 其他模式](#策略模式 vs 其他模式)
[策略模式 vs 工厂模式](#策略模式 vs 工厂模式)
[策略模式 vs 状态模式](#策略模式 vs 状态模式)
C#上位机策略模式
生活中的比喻:支付方式 💳
想象你去超市结账,有多种支付方式:
顾客 → 选择支付方式 → 完成支付
↓ ↓ ↓
你 支付宝/微信/现金/信用卡 收银
关键点 :支付算法可以随时切换,但支付的结果相同(完成交易)。
代码例子
场景:计算器程序
cs
using System;
// 步骤1:定义策略接口
public interface ICalculationStrategy
{
decimal Calculate(decimal a, decimal b);
}
// 步骤2:实现具体策略
public class AddStrategy : ICalculationStrategy
{
public decimal Calculate(decimal a, decimal b)
{
return a + b;
}
}
public class SubtractStrategy : ICalculationStrategy
{
public decimal Calculate(decimal a, decimal b)
{
return a - b;
}
}
public class MultiplyStrategy : ICalculationStrategy
{
public decimal Calculate(decimal a, decimal b)
{
return a * b;
}
}
public class DivideStrategy : ICalculationStrategy
{
public decimal Calculate(decimal a, decimal b)
{
if (b == 0) throw new DivideByZeroException();
return a / b;
}
}
// 步骤3:策略上下文
public class Calculator
{
private ICalculationStrategy _strategy;
// 设置策略(可以在运行时改变!)
public void SetStrategy(ICalculationStrategy strategy)
{
_strategy = strategy;
Console.WriteLine($"切换策略:{strategy.GetType().Name}");
}
// 执行策略
public decimal Execute(decimal a, decimal b)
{
if (_strategy == null)
{
throw new InvalidOperationException("请先设置计算策略!");
}
return _strategy.Calculate(a, b);
}
}
// 步骤4:使用
class Program
{
static void Main()
{
Console.WriteLine("🧮 策略模式:计算器示例\n");
var calculator = new Calculator();
// 测试加法
calculator.SetStrategy(new AddStrategy());
Console.WriteLine($"5 + 3 = {calculator.Execute(5, 3)}");
// 切换到减法
calculator.SetStrategy(new SubtractStrategy());
Console.WriteLine($"10 - 4 = {calculator.Execute(10, 4)}");
// 切换到乘法
calculator.SetStrategy(new MultiplyStrategy());
Console.WriteLine($"6 × 7 = {calculator.Execute(6, 7)}");
// 切换到除法
calculator.SetStrategy(new DivideStrategy());
Console.WriteLine($"15 ÷ 3 = {calculator.Execute(15, 3)}");
Console.WriteLine("\n🎯 演示完成!");
}
}
上位机实际应用:数据保存策略
场景:上位机采集的数据可以保存到不同地方
cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
// 数据类
public class SensorData
{
public DateTime Timestamp { get; set; }
public string DeviceId { get; set; }
public double Value { get; set; }
public string Unit { get; set; }
public override string ToString()
{
return $"[{Timestamp:HH:mm:ss}] {DeviceId}: {Value:F2}{Unit}";
}
}
// 步骤1:定义保存策略接口
public interface IDataSaveStrategy
{
Task SaveAsync(IEnumerable<SensorData> data);
string StrategyName { get; }
}
// 步骤2:具体策略实现
// 策略1:保存到文本文件
public class TextFileSaveStrategy : IDataSaveStrategy
{
private string _filePath;
public TextFileSaveStrategy(string filePath)
{
_filePath = filePath;
}
public string StrategyName => "文本文件";
public async Task SaveAsync(IEnumerable<SensorData> data)
{
var lines = new List<string>();
foreach (var item in data)
{
lines.Add(item.ToString());
}
await File.AppendAllLinesAsync(_filePath, lines);
Console.WriteLine($"✅ 已保存 {lines.Count} 条数据到文本文件: {_filePath}");
}
}
// 策略2:保存到JSON文件
public class JsonSaveStrategy : IDataSaveStrategy
{
private string _filePath;
public JsonSaveStrategy(string filePath)
{
_filePath = filePath;
}
public string StrategyName => "JSON文件";
public async Task SaveAsync(IEnumerable<SensorData> data)
{
var json = JsonSerializer.Serialize(data, new JsonSerializerOptions
{
WriteIndented = true
});
await File.WriteAllTextAsync(_filePath, json);
Console.WriteLine($"✅ 已保存 {data} 条数据到JSON文件: {_filePath}");
}
}
// 策略3:保存到数据库(模拟)
public class DatabaseSaveStrategy : IDataSaveStrategy
{
private string _connectionString;
public DatabaseSaveStrategy(string connectionString)
{
_connectionString = connectionString;
}
public string StrategyName => "数据库";
public async Task SaveAsync(IEnumerable<SensorData> data)
{
// 模拟数据库保存
int count = 0;
foreach (var item in data)
{
// 这里实际应该执行SQL插入
await Task.Delay(10); // 模拟数据库操作延迟
count++;
}
Console.WriteLine($"✅ 已保存 {count} 条数据到数据库");
}
}
// 策略4:保存到Excel(模拟)
public class ExcelSaveStrategy : IDataSaveStrategy
{
private string _filePath;
public ExcelSaveStrategy(string filePath)
{
_filePath = filePath;
}
public string StrategyName => "Excel文件";
public async Task SaveAsync(IEnumerable<SensorData> data)
{
// 模拟Excel保存(实际应该用EPPlus等库)
var excelData = new StringBuilder();
excelData.AppendLine("时间,设备ID,数值,单位");
foreach (var item in data)
{
excelData.AppendLine($"{item.Timestamp:yyyy-MM-dd HH:mm:ss},{item.DeviceId},{item.Value},{item.Unit}");
}
await File.WriteAllTextAsync(_filePath, excelData.ToString());
Console.WriteLine($"✅ 已保存 {data} 条数据到Excel: {_filePath}");
}
}
// 步骤3:策略上下文
public class DataSaver
{
private IDataSaveStrategy _strategy;
// 当前策略
public string CurrentStrategy => _strategy?.StrategyName ?? "未设置";
// 设置策略
public void SetSaveStrategy(IDataSaveStrategy strategy)
{
_strategy = strategy;
Console.WriteLine($"🔄 切换保存策略为: {strategy.StrategyName}");
}
// 执行保存
public async Task SaveDataAsync(IEnumerable<SensorData> data)
{
if (_strategy == null)
{
throw new InvalidOperationException("请先设置保存策略!");
}
Console.WriteLine($"\n💾 开始保存数据...");
Console.WriteLine($"📊 数据量: {data} 条");
Console.WriteLine($"🎯 使用策略: {_strategy.StrategyName}");
var startTime = DateTime.Now;
await _strategy.SaveAsync(data);
var elapsed = DateTime.Now - startTime;
Console.WriteLine($"⏱️ 保存耗时: {elapsed.TotalMilliseconds:F0}ms");
}
}
// 模拟数据生成
public class DataGenerator
{
public static List<SensorData> GenerateTestData(int count)
{
var data = new List<SensorData>();
var random = new Random();
var now = DateTime.Now;
for (int i = 0; i < count; i++)
{
data.Add(new SensorData
{
Timestamp = now.AddSeconds(-i * 10),
DeviceId = $"DEV_{random.Next(1, 4):000}",
Value = 20 + random.NextDouble() * 10,
Unit = "°C"
});
}
return data;
}
}
// 步骤4:使用
class Program
{
static async Task Main()
{
Console.WriteLine("💾 上位机数据保存策略示例\n");
// 生成测试数据
var testData = DataGenerator.GenerateTestData(50);
Console.WriteLine($"📊 生成 {testData.Count} 条测试数据\n");
// 创建数据保存器
var dataSaver = new DataSaver();
// 演示不同保存策略
Console.WriteLine("🧪 测试不同保存策略:\n");
// 1. 保存到文本文件
dataSaver.SetSaveStrategy(new TextFileSaveStrategy("data.txt"));
await dataSaver.SaveDataAsync(testData.Take(10));
// 2. 切换到JSON文件
dataSaver.SetSaveStrategy(new JsonSaveStrategy("data.json"));
await dataSaver.SaveDataAsync(testData.Take(5));
// 3. 切换到数据库(模拟)
dataSaver.SetSaveStrategy(new DatabaseSaveStrategy("Server=localhost;Database=Test"));
await dataSaver.SaveDataAsync(testData.Take(20));
// 4. 切换到Excel(模拟)
dataSaver.SetSaveStrategy(new ExcelSaveStrategy("data.csv"));
await dataSaver.SaveDataAsync(testData);
Console.WriteLine("\n🎯 所有保存策略测试完成!");
}
}
上位机通信协议策略
场景:支持多种通信协议
cs
using System;
using System.Text;
using System.Threading.Tasks;
// 策略接口:通信协议
public interface ICommunicationProtocol
{
Task<string> SendAndReceiveAsync(string message);
string ProtocolName { get; }
bool Connect();
void Disconnect();
}
// 具体策略1:Modbus TCP
public class ModbusTcpProtocol : ICommunicationProtocol
{
private string _ipAddress;
private int _port;
public ModbusTcpProtocol(string ip, int port = 502)
{
_ipAddress = ip;
_port = port;
}
public string ProtocolName => "Modbus TCP";
public bool Connect()
{
Console.WriteLine($"🔌 连接Modbus TCP: {_ipAddress}:{_port}");
// 实际实现TCP连接
return true;
}
public void Disconnect()
{
Console.WriteLine("🔌 断开Modbus TCP连接");
}
public async Task<string> SendAndReceiveAsync(string message)
{
Console.WriteLine($"📡 Modbus TCP发送: {message}");
// 模拟Modbus协议处理
await Task.Delay(100);
// 模拟返回数据
return $"Modbus响应: {message.ToUpper()}";
}
}
// 具体策略2:串口通信
public class SerialPortProtocol : ICommunicationProtocol
{
private string _portName;
private int _baudRate;
public SerialPortProtocol(string portName, int baudRate = 9600)
{
_portName = portName;
_baudRate = baudRate;
}
public string ProtocolName => "串口通信";
public bool Connect()
{
Console.WriteLine($"🔌 打开串口: {_portName}, 波特率: {_baudRate}");
// 实际打开串口
return true;
}
public void Disconnect()
{
Console.WriteLine($"🔌 关闭串口: {_portName}");
}
public async Task<string> SendAndReceiveAsync(string message)
{
Console.WriteLine($"📡 串口发送: {message}");
// 模拟串口通信延迟
await Task.Delay(200);
// 模拟返回数据
return $"串口响应: {message}";
}
}
// 具体策略3:OPC UA
public class OpcUaProtocol : ICommunicationProtocol
{
private string _serverUrl;
public OpcUaProtocol(string serverUrl)
{
_serverUrl = serverUrl;
}
public string ProtocolName => "OPC UA";
public bool Connect()
{
Console.WriteLine($"🔌 连接OPC UA服务器: {_serverUrl}");
// 实际连接OPC UA服务器
return true;
}
public void Disconnect()
{
Console.WriteLine("🔌 断开OPC UA连接");
}
public async Task<string> SendAndReceiveAsync(string message)
{
Console.WriteLine($"📡 OPC UA读取: {message}");
// 模拟OPC UA通信
await Task.Delay(150);
// 模拟返回数据
return $"OPC UA值: {DateTime.Now:HH:mm:ss}";
}
}
// 策略上下文:通信管理器
public class CommunicationManager
{
private ICommunicationProtocol _protocol;
// 当前协议
public string CurrentProtocol => _protocol?.ProtocolName ?? "未设置";
// 设置协议
public bool SetProtocol(ICommunicationProtocol protocol)
{
if (_protocol != null)
{
_protocol.Disconnect();
}
_protocol = protocol;
Console.WriteLine($"🔄 切换通信协议: {protocol.ProtocolName}");
return _protocol.Connect();
}
// 发送命令
public async Task<string> SendCommandAsync(string command)
{
if (_protocol == null)
{
throw new InvalidOperationException("请先设置通信协议!");
}
Console.WriteLine($"\n📤 发送命令: {command}");
Console.WriteLine($"📡 使用协议: {_protocol.ProtocolName}");
var response = await _protocol.SendAndReceiveAsync(command);
Console.WriteLine($"📥 收到响应: {response}");
return response;
}
// 断开连接
public void Disconnect()
{
_protocol?.Disconnect();
}
}
// 使用示例
class Program
{
static async Task Main()
{
Console.WriteLine("📡 上位机多协议通信示例\n");
var commManager = new CommunicationManager();
// 测试Modbus TCP
Console.WriteLine("1. 测试Modbus TCP:");
commManager.SetProtocol(new ModbusTcpProtocol("192.168.1.100"));
await commManager.SendCommandAsync("Read Holding Registers 40001");
await commManager.SendCommandAsync("Write Coil 00001 ON");
// 测试串口通信
Console.WriteLine("\n2. 测试串口通信:");
commManager.SetProtocol(new SerialPortProtocol("COM3", 115200));
await commManager.SendCommandAsync("AT+READ?");
await commManager.SendCommandAsync("AT+SET=123");
// 测试OPC UA
Console.WriteLine("\n3. 测试OPC UA:");
commManager.SetProtocol(new OpcUaProtocol("opc.tcp://localhost:4840"));
await commManager.SendCommandAsync("ns=2;s=Temperature");
await commManager.SendCommandAsync("ns=2;s=Pressure");
commManager.Disconnect();
Console.WriteLine("\n🎯 通信测试完成!");
}
}
策略工厂模式
结合工厂模式,自动创建策略
cs
using System;
using System.Collections.Generic;
// 策略工厂
public class StrategyFactory
{
private Dictionary<string, Func<object>> _strategies = new Dictionary<string, Func<object>>();
// 注册策略
public void Register<T>(string key, Func<T> creator) where T : class
{
_strategies[key] = () => creator();
}
// 创建策略
public T Create<T>(string key) where T : class
{
if (_strategies.TryGetValue(key, out var creator))
{
return creator() as T;
}
throw new ArgumentException($"未找到策略: {key}");
}
// 获取所有可用策略
public IEnumerable<string> GetAvailableStrategies()
{
return _strategies.Keys;
}
}
// 使用策略工厂
public class PaymentProcessor
{
private StrategyFactory _factory;
private IPaymentStrategy _currentStrategy;
public PaymentProcessor()
{
_factory = new StrategyFactory();
// 注册支付策略
_factory.Register<IPaymentStrategy>("alipay", () => new AlipayStrategy());
_factory.Register<IPaymentStrategy>("wechat", () => new WechatPayStrategy());
_factory.Register<IPaymentStrategy>("creditcard", () => new CreditCardStrategy());
_factory.Register<IPaymentStrategy>("cash", () => new CashStrategy());
}
// 动态切换支付方式
public void SetPaymentMethod(string method)
{
_currentStrategy = _factory.Create<IPaymentStrategy>(method);
Console.WriteLine($"💳 切换到支付方式: {method}");
}
public bool ProcessPayment(decimal amount)
{
return _currentStrategy?.Pay(amount) ?? false;
}
// 显示所有可用支付方式
public void ShowAvailableMethods()
{
Console.WriteLine("可用支付方式:");
foreach (var method in _factory.GetAvailableStrategies())
{
Console.WriteLine($" - {method}");
}
}
}
// 支付策略接口和实现
public interface IPaymentStrategy
{
bool Pay(decimal amount);
string MethodName { get; }
}
public class AlipayStrategy : IPaymentStrategy
{
public string MethodName => "支付宝";
public bool Pay(decimal amount)
{
Console.WriteLine($"📱 支付宝支付 {amount:C} 元");
return true;
}
}
public class WechatPayStrategy : IPaymentStrategy
{
public string MethodName => "微信支付";
public bool Pay(decimal amount)
{
Console.WriteLine($"💬 微信支付 {amount:C} 元");
return true;
}
}
// 使用
class Program
{
static void Main()
{
var processor = new PaymentProcessor();
processor.ShowAvailableMethods();
Console.WriteLine("\n模拟购物流程:");
processor.SetPaymentMethod("alipay");
processor.ProcessPayment(128.50m);
processor.SetPaymentMethod("wechat");
processor.ProcessPayment(59.90m);
processor.SetPaymentMethod("creditcard");
processor.ProcessPayment(299.00m);
}
}
7. 策略模式的优点和缺点
✅ 优点:
-
开闭原则:新增策略不需要修改现有代码
-
避免条件语句:代替复杂的 if-else 或 switch-case
-
运行时切换:可以在程序运行时动态改变行为
-
代码复用:策略可以在不同上下文中复用
-
易于测试:每个策略可以单独测试
❌ 缺点:
-
策略类增多:每个策略一个类,可能导致类爆炸
-
客户端必须了解策略:需要知道不同策略的区别
-
通信开销:策略和上下文之间可能需要传递数据
策略模式 vs 其他模式
策略模式 vs 工厂模式
// 工厂模式:关心"创建什么对象"
var logger = LoggerFactory.CreateLogger("file"); // 创建文件日志器
// 策略模式:关心"使用什么算法"
sorter.SetStrategy(new QuickSortStrategy()); // 使用快速排序算法
策略模式 vs 状态模式
// 策略模式:客户端主动选择策略
calculator.SetStrategy(new AddStrategy()); // 我选择加法
// 状态模式:状态自动转换
order.SetState(new PaidState()); // 支付后自动变为已支付状态
实际应用场景
场景1:数据验证策略
// 不同数据类型的验证策略
public interface IValidationStrategy
{
bool Validate(string input);
}
public class EmailValidationStrategy : IValidationStrategy { }
public class PhoneValidationStrategy : IValidationStrategy { }
public class NumberValidationStrategy : IValidationStrategy { }
public class DateValidationStrategy : IValidationStrategy { }
// 使用时:
validator.SetStrategy(new EmailValidationStrategy());
validator.Validate("test@example.com");
场景2:报表导出策略
// 导出为不同格式
public interface IExportStrategy
{
byte[] Export(ReportData data);
}
public class PdfExportStrategy : IExportStrategy { }
public class ExcelExportStrategy : IExportStrategy { }
public class CsvExportStrategy : IExportStrategy { }
public class HtmlExportStrategy : IExportStrategy { }
场景3:图像处理策略
// 不同的图像处理算法
public interface IImageProcessStrategy
{
Bitmap Process(Bitmap image);
}
public class GrayscaleStrategy : IImageProcessStrategy { }
public class BlurStrategy : IImageProcessStrategy { }
public class SharpenStrategy : IImageProcessStrategy { }
public class ResizeStrategy : IImageProcessStrategy { }
在上位机开发中,策略模式特别适合处理:
-
多种通信协议
-
多种数据保存方式
-
多种数据处理算法
-
多种显示格式
-
多种控制策略