You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将两个功能相近的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 02:21:16