如何将两个功能相近的Blazor Razor组件合并为单一动态组件?
解决方案:用泛型+接口抽象实现通用Razor组件
完全可以通过抽象服务接口+泛型组件的方式,把两个重复的组件合并成一个通用组件,彻底避免重复修改的负担。核心思路是把不同的服务和模型抽象成统一接口,让泛型组件依赖接口而非具体实现。
步骤1:抽象服务接口
先为不同业务的服务定义通用接口,统一方法签名:
// 返利服务通用接口 public interface IRebateService<TRebate> { Task<List<TRebate>> GetRebatesAsync(); // 补充其他通用业务方法,比如保存、删除等 } // 费率服务通用接口 public interface IRateService { Task<List<RateModel>> GetRatesAsync(); // 补充对应业务的通用方法 } // 灯具类型服务通用接口 public interface ILightTypeService { Task<List<DdlModel>> GetLightTypesAsync(); // 补充对应业务的通用方法 }
让现有具体服务实现上述接口:
// AreaLightRebatesService实现返利服务接口 public class AreaLightRebatesService : IRebateService<AreaLightRebate> { public async Task<List<AreaLightRebate>> GetRebatesAsync() { // 保留原有业务逻辑 } // 其他方法实现 } // DuskToDawnRebateService实现返利服务接口 public class DuskToDawnRebateService : IRebateService<DuskToDawnLightRebate> { public async Task<List<DuskToDawnLightRebate>> GetRebatesAsync() { // 保留原有业务逻辑 } // 其他方法实现 } // AreaLightTypeService同时实现费率和灯具类型接口 public class AreaLightTypeService : IRateService, ILightTypeService { public async Task<List<RateModel>> GetRatesAsync() { // 保留原有逻辑 } public async Task<List<DdlModel>> GetLightTypesAsync() { // 保留原有逻辑 } } // DuskToDawnRatesService实现费率接口 public class DuskToDawnRatesService : IRateService { public async Task<List<RateModel>> GetRatesAsync() { // 保留原有逻辑 } } // DtdLightTypeService实现灯具类型接口 public class DtdLightTypeService : ILightTypeService { public async Task<List<DdlModel>> GetLightTypesAsync() { // 保留原有逻辑 } }
步骤2:创建泛型Razor组件
新建通用的RebatesComponent.razor,依赖抽象接口和泛型参数:
@typeparam TRebate @typeparam TRebateService where TRebateService : IRebateService<TRebate> @typeparam TRateService where TRateService : IRateService @typeparam TLightTypeService where TLightTypeService : ILightTypeService @inject TRebateService RebateService @inject TRateService RateService @inject TLightTypeService LightTypeService @inject PoleTypeService PoleTypeService @inject TaxRateService TaxService @inject InterestRateService InterestService @inject IJSRuntime JSRuntime <!-- 保留原有组件的UI结构,把绑定的具体模型替换为TRebate --> <div class="rebate-container"> <!-- 示例:渲染返利列表 --> @foreach (var rebate in Rebates) { <div class="rebate-item">@rebate.Name</div> } </div> @code { private List<TRebate> Rebates { get; set; } = new(); public string SelectedItemPlaceholder { get; set; } private List<DdlModel> LightTypesDdl { get; set; } = new(); protected override async Task OnInitializedAsync() { // 复用原有逻辑,全部调用接口方法 Rebates = await RebateService.GetRebatesAsync(); LightTypesDdl = await LightTypeService.GetLightTypesAsync(); // 其他原有逻辑,比如获取费率、税率等,直接保留 } // 原有组件的其他通用方法,全部保留,替换具体模型为TRebate }
步骤3:使用泛型组件
在需要的页面或组件中,直接调用泛型组件并指定对应的模型和服务类型:
<!-- 渲染AreaLightRebates功能 --> <RebatesComponent TRebate="AreaLightRebate" TRebateService="AreaLightRebatesService" TRateService="AreaLightTypeService" TLightTypeService="AreaLightTypeService" /> <!-- 渲染DuskToDawnRebates功能 --> <RebatesComponent TRebate="DuskToDawnLightRebate" TRebateService="DuskToDawnRebateService" TRateService="DuskToDawnRatesService" TLightTypeService="DtdLightTypeService" />
额外优化(可选)
如果觉得泛型参数过多,可以把相关服务和模型封装成业务标记类,或者用工厂模式动态获取服务,但上述方式已经能解决核心问题,且逻辑清晰易维护。
内容的提问来源于stack exchange,提问作者Pavan Sista
相关产品推荐
相关产品推荐

