基于接口的工厂模式实现响应类:如何避免强制类型转换?
解决工厂模式下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
相关产品推荐
相关产品推荐

