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

基于接口的工厂模式实现响应类:如何避免强制类型转换?

解决工厂模式下Response无需强制类型转换的问题

你的问题核心在于接口方法的返回类型是通用的IResponse,即便子类重写方法时返回了具体的子类实例,调用时编译器只能识别为IResponse,因此必须强制转换。要解决这个问题,我们可以用泛型接口结合奇异递归模板模式(CRTP),让每个子类的方法返回自身类型,从而避免强制转换。

第一步:重构为泛型接口

首先修改IResponse为泛型接口,约束类型参数为实现该接口的子类,这样SetExceptionResponse就能返回具体的子类类型:

public interface IResponse<T> where T : IResponse<T>
{
    int ErrorCode { get; set; }
    HeaderResponse HeaderResponse { get; set; }
    // 现在返回类型是T,即具体的子类
    T SetExceptionResponse(int code, string title, string[] errors);
}

第二步:创建泛型基类(复用通用逻辑)

为了避免每个子类重复编写创建错误Header的代码,我们可以创建一个抽象泛型基类,实现通用逻辑并定义抽象方法让子类实现:

public abstract class ResponseBase<T> : IResponse<T> where T : ResponseBase<T>
{
    public int ErrorCode { get; set; }
    public HeaderResponse HeaderResponse { get; set; } = null;

    // 抽象方法,由子类返回自身实例
    public abstract T SetExceptionResponse(int code, string title, string[] errors);

    // 抽离通用的错误Header创建逻辑
    protected HeaderResponse BuildErrorHeader(int code, string title, string[] errors)
    {
        var header = new HeaderResponse();
        if (errors.Length > 0)
        {
            foreach (var error in errors)
                header.ErrorList.Add(error);
        }
        header.Title = title;
        header.StatusCode = code;
        return header;
    }
}

第三步:修改子类继承泛型基类

让你的具体Response子类继承ResponseBase<T>,并实现SetExceptionResponse方法返回自身实例:

public class DeleteShipmentResponse : ResponseBase<DeleteShipmentResponse>
{
    public string Value { get; set; }

    public override string ToString()
    {
        return JsonConvert.SerializeObject(this);
    }

    public override DeleteShipmentResponse SetExceptionResponse(int code, string title, string[] errors)
    {
        var errorHeader = BuildErrorHeader(code, title, errors);
        return new DeleteShipmentResponse 
        { 
            ErrorCode = code, 
            HeaderResponse = errorHeader 
        };
    }
}

// 同理,你的ShipmentResponse也可以这样修改:
public class ShipmentResponse : ResponseBase<ShipmentResponse>
{
    // 你的子类属性...
    public override ShipmentResponse SetExceptionResponse(int code, string title, string[] errors)
    {
        var errorHeader = BuildErrorHeader(code, title, errors);
        return new ShipmentResponse 
        { 
            ErrorCode = code, 
            HeaderResponse = errorHeader 
        };
    }
}

// 如果需要基础的Response类,也可以创建:
public class BasicResponse : ResponseBase<BasicResponse>
{
    public override BasicResponse SetExceptionResponse(int code, string title, string[] errors)
    {
        var errorHeader = BuildErrorHeader(code, title, errors);
        return new BasicResponse 
        { 
            ErrorCode = code, 
            HeaderResponse = errorHeader 
        };
    }
}

第四步:更新工厂类适配泛型

调整工厂类的泛型方法,确保返回具体的子类类型:

public static class ResponseFactory
{
    public static BasicResponse CreateBasicResponse()
    {
        return new BasicResponse();
    }

    public static DeleteShipmentResponse CreateDeleteResponse()
    {
        return new DeleteShipmentResponse();
    }

    public static ShipmentResponse CreateShipmentResponse()
    {
        return new ShipmentResponse();
    }

    public static T CreateResponse<T>() where T : IResponse<T>
    {
        if (typeof(T) == typeof(BasicResponse))
            return (T)(object)CreateBasicResponse();
        if (typeof(T) == typeof(DeleteShipmentResponse))
            return (T)(object)CreateDeleteResponse();
        if (typeof(T) == typeof(ShipmentResponse))
            return (T)(object)CreateShipmentResponse();
        
        throw new ArgumentOutOfRangeException(nameof(T), 
            $"Unrecognized response type: {typeof(T).FullName}");
    }
}

最终调用方式(无需强制转换)

现在你可以直接调用,编译器会自动识别返回类型:

// 无需强制转换,直接得到DeleteShipmentResponse实例
DeleteShipmentResponse result = ResponseFactory.CreateResponse<DeleteShipmentResponse>()
    .SetExceptionResponse(500, "Exception in DeleteShipment()", new string[] { ex.Message });

为什么这个方案有效?

通过泛型接口IResponse<T>,我们让每个子类明确声明自己作为方法的返回类型,编译器可以在编译时就确定返回的具体类型,而不是只能识别为通用的IResponse。同时,泛型基类帮助我们复用了通用的错误Header创建逻辑,减少了代码重复。

内容的提问来源于stack exchange,提问作者Julien Martin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 09:17:41