如何为.NET3.5/C#7环境下的WebForm后端代码应用设计模式?
我来帮你拆解一下怎么把Bridge、Command和Builder模式用到你的WebForm代码里,顺便解决泛型在Repository里的问题——毕竟.NET3.5和C#7的组合虽然不能用最新特性,但这些经典模式完全适配:
一、逐个应用设计模式
1. Builder模式:统一请求的构建与验证逻辑
你现在在Page_Load里分散了DTO创建、字段验证和实体构建的逻辑,用Builder模式可以把这些逻辑抽离到专门的类里,让页面代码更清爽,也方便复用和扩展。
先创建抽象Builder基类,定义通用的构建流程:
public abstract class RequestBuilder<TRequest, TDto> where TRequest : StandardRequest where TDto : StandardRequestDTO { // 从Form表单生成DTO public abstract TDto CreateDtoFromForm(HttpRequest form); // 验证DTO字段合法性 public abstract void Validate(TDto dto); // 从DTO构建请求实体 public abstract TRequest BuildRequest(TDto dto); }
然后分别实现标准请求和特殊请求的Builder,把你页面里的验证逻辑移过来:
// 标准请求Builder public class StandardRequestBuilder : RequestBuilder<StandardRequest, StandardRequestDTO> { public override StandardRequestDTO CreateDtoFromForm(HttpRequest form) { return new StandardRequestDTO { Name = form["Name"], RequestType = 0 }; } public override void Validate(StandardRequestDTO dto) { if (string.IsNullOrWhiteSpace(dto.Name)) throw new InvalidOperationException("请求名称不能为空"); // 其他标准请求的验证规则 } public override StandardRequest BuildRequest(StandardRequestDTO dto) { return StandardRequest.Create(dto); } } // 特殊请求Builder public class SpecialRequestBuilder : RequestBuilder<SpecialRequest, SpecialRequestDTO> { public override SpecialRequestDTO CreateDtoFromForm(HttpRequest form) { return new SpecialRequestDTO { Name = form["Name"], RequestType = 1, Desc = form["Desc"] }; } public override void Validate(SpecialRequestDTO dto) { if (string.IsNullOrWhiteSpace(dto.Desc)) throw new InvalidOperationException("特殊请求描述不能为空"); // 其他特殊请求的验证规则 } public override SpecialRequest BuildRequest(SpecialRequestDTO dto) { // 注意:你原来的Create方法写错了,应该返回SpecialRequest实例 return SpecialRequest.Create(dto); } }
2. Bridge模式:分离请求类型与持久化逻辑
Bridge模式的核心是抽象与实现分离,这里可以把请求实体(抽象部分)和数据库操作(实现部分)拆开,解决你Repository里多个Save方法的冗余问题,同时方便后续新增请求类型。
先定义持久化操作的接口:
public interface IRequestPersistence<T> where T : StandardRequest { void Save(T request); }
然后为两种请求实现各自的持久化逻辑:
// 标准请求持久化实现 public class StandardRequestPersistence : IRequestPersistence<StandardRequest> { public void Save(StandardRequest request) { var query = $"INSERT INTO Requests (Name, RequestType) Values(@{nameof(request.Name)}, @{nameof(request.RequestType)})"; // 你的SQLCommand执行代码放在这里 } } // 特殊请求持久化实现 public class SpecialRequestPersistence : IRequestPersistence<SpecialRequest> { public void Save(SpecialRequest request) { var query = $"INSERT INTO Requests (Name, RequestType, Desc) VALUES(@{nameof(request.Name)}, @{nameof(request.RequestType)}, @{nameof(request.Desc)})"; // 你的SQLCommand执行代码放在这里 } }
最后改造Repository,用泛型方法统一处理保存,同时通过字典注册不同的持久化实现:
public class Repository { private readonly Dictionary<Type, object> _persistenceHandlers = new Dictionary<Type, object>(); public Repository() { // 注册两种请求的持久化处理器 _persistenceHandlers.Add(typeof(StandardRequest), new StandardRequestPersistence()); _persistenceHandlers.Add(typeof(SpecialRequest), new SpecialRequestPersistence()); } public void SaveRequest<T>(T request) where T : StandardRequest { if (_persistenceHandlers.TryGetValue(typeof(T), out var handler)) { // 转换成对应的泛型持久化接口并执行保存 ((IRequestPersistence<T>)handler).Save(request); } else { throw new NotSupportedException($"暂不支持保存{typeof(T).Name}类型的请求"); } } }
3. Command模式:封装保存操作的执行逻辑
Command模式适合把操作封装成独立的对象,这样你可以轻松添加日志、异常处理、甚至撤销(如果需要的话)等扩展逻辑,而不用修改核心的保存代码。
先定义Command接口:
public interface IRequestCommand { void Execute(); }
然后实现两种请求的保存命令:
// 标准请求保存命令 public class SaveStandardRequestCommand : IRequestCommand { private readonly StandardRequest _request; private readonly Repository _repository; public SaveStandardRequestCommand(StandardRequest request, Repository repository) { _request = request; _repository = repository; } public void Execute() { _repository.SaveRequest(_request); // 这里可以添加日志:比如记录标准请求保存成功 } } // 特殊请求保存命令 public class SaveSpecialRequestCommand : IRequestCommand { private readonly SpecialRequest _request; private readonly Repository _repository; public SaveSpecialRequestCommand(SpecialRequest request, Repository repository) { _request = request; _repository = repository; } public void Execute() { _repository.SaveRequest(_request); // 这里可以添加日志:比如记录特殊请求保存成功 } }
再写一个命令执行器,统一处理命令的执行和异常:
public class CommandInvoker { public void ExecuteCommand(IRequestCommand command) { try { command.Execute(); } catch (Exception ex) { // 统一记录异常日志 throw new InvalidOperationException("保存请求失败", ex); } } }
二、改造后的Page_Load代码
现在把上面的模式整合起来,你的页面后端代码会变得非常简洁:
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) return; string requestTypeStr = Request.Form["requestTypeStr"]; if (string.IsNullOrEmpty(requestTypeStr) || !int.TryParse(requestTypeStr, out int requestType)) return; IRequestCommand command = null; switch (requestType) { case 0: var stdBuilder = new StandardRequestBuilder(); var stdDto = stdBuilder.CreateDtoFromForm(Request); stdBuilder.Validate(stdDto); var stdRequest = stdBuilder.BuildRequest(stdDto); command = new SaveStandardRequestCommand(stdRequest, _repository); break; case 1: var specialBuilder = new SpecialRequestBuilder(); var specialDto = specialBuilder.CreateDtoFromForm(Request); specialBuilder.Validate(specialDto); var specialRequest = specialBuilder.BuildRequest(specialDto); command = new SaveSpecialRequestCommand(specialRequest, _repository); break; default: return; } var invoker = new CommandInvoker(); invoker.ExecuteCommand(command); }
三、关于泛型的问题说明
你之前在Repository里调用泛型方法遇到困难,主要是因为原来的Repository没有抽象出持久化逻辑。现在通过Bridge模式的改造,我们用SaveRequest<T>泛型方法统一处理,同时通过字典注册不同类型的持久化处理器,完美适配.NET3.5的泛型支持——这个版本对泛型的基础特性支持是完全没问题的,C#7的语法也可以正常使用。
另外,注意修正你原来SpecialRequest.Create方法的错误:原来的代码返回了SpecialRequestDTO实例,应该返回SpecialRequest,不然会出现类型错误。
内容的提问来源于stack exchange,提问作者Kristianne Nerona

