C#上位机策略模式

目录

C#上位机策略模式

[生活中的比喻:支付方式 💳](#生活中的比喻:支付方式 💳)

代码例子

场景:计算器程序

上位机实际应用:数据保存策略

场景:上位机采集的数据可以保存到不同地方

上位机通信协议策略

场景:支持多种通信协议

策略工厂模式

结合工厂模式,自动创建策略

[7. 策略模式的优点和缺点](#7. 策略模式的优点和缺点)

[✅ 优点:](#✅ 优点:)

[❌ 缺点:](#❌ 缺点:)

[策略模式 vs 其他模式](#策略模式 vs 其他模式)

[策略模式 vs 工厂模式](#策略模式 vs 工厂模式)

[策略模式 vs 状态模式](#策略模式 vs 状态模式)

实际应用场景

场景1:数据验证策略

场景2:报表导出策略

场景3:图像处理策略

在上位机开发中,策略模式特别适合处理:


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. 策略模式的优点和缺点

✅ 优点:

  1. 开闭原则:新增策略不需要修改现有代码

  2. 避免条件语句:代替复杂的 if-else 或 switch-case

  3. 运行时切换:可以在程序运行时动态改变行为

  4. 代码复用:策略可以在不同上下文中复用

  5. 易于测试:每个策略可以单独测试

❌ 缺点:

  1. 策略类增多:每个策略一个类,可能导致类爆炸

  2. 客户端必须了解策略:需要知道不同策略的区别

  3. 通信开销:策略和上下文之间可能需要传递数据

策略模式 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 { }

在上位机开发中,策略模式特别适合处理:

  • 多种通信协议

  • 多种数据保存方式

  • 多种数据处理算法

  • 多种显示格式

  • 多种控制策略

相关推荐
2301_789015622 小时前
C++:set/multiset和map/multimap文档详细解析
c语言·开发语言·c++·vscode·排序算法·set·map
CoderCodingNo2 小时前
【GESP】C++五级真题(数论-素数思想考点) luogu-P10720 [GESP202406 五级] 小杨的幸运数字
开发语言·c++·算法
zmzb01032 小时前
C++课后习题训练记录Day59
开发语言·c++
黎雁·泠崖2 小时前
C 语言文件操作进阶:格式化读写 + 二进制读写 + 随机读写进阶全解
c语言·开发语言
baivfhpwxf20232 小时前
C# 语言 SQL Server 批量更新
服务器·windows·c#
talenteddriver2 小时前
web: jwt令牌构成、创建的基本流程及原理
java·开发语言·python·网络协议·web
这周也會开心2 小时前
双栈实现队列以及双队列实现栈
java·开发语言
“抚琴”的人2 小时前
C#上位机状态模式
c#·状态模式
Bruce_kaizy2 小时前
c++图论——最短路之Johnson算法
开发语言·数据结构·c++·算法·图论