如何用抽象工厂处理构造参数不同的接口实现及服务注入问题?
问题描述
当接口实现类的构造函数一致时,所有功能运行正常,但当构造函数存在差异时,遇到了难题。这种实现方式是否可行,还是存在架构层面的问题?
相关代码如下:
public class CategoryViewFactory : ICategoryViewFactory { private readonly ActiveProgressions _activeProgressions; public CategoryViewFactory(ActiveProgressions activeProgressions) { _activeProgressions = activeProgressions; } public ICategoryView? Create(CategoryType type, Category category) { return type switch { CategoryType.Category => new CategoryView(category), CategoryType.Subcategory => new SubcategoryView(category, _activeProgressions), _ => null }; } }
补充疑问:
- ActiveProgressions是通过容器注入的单例服务,这种实现是否合理?
- 若ActiveProgressions为瞬态服务,该如何创建SubcategoryView?认为在
Create()方法中添加额外参数的方案并不理想,但似乎是当前唯一的解决办法。
解答
一、单例ActiveProgressions时的实现合理性
当前实现是合理的,核心原因如下:
- 单例服务的设计目标就是被多个消费者共享,工厂类通过构造函数注入持有单例
ActiveProgressions的引用,不存在生命周期冲突问题。 - 遵循依赖注入原则,工厂类的依赖由外部注入而非内部硬编码,保证了可测试性——你可以轻松替换
ActiveProgressions的模拟实现来验证工厂逻辑。 - 潜在的小局限:如果后续
CategoryView也需要依赖其他服务,直接new的写法会让工厂类职责逐渐膨胀,但当前场景下是完全可控的。
二、瞬态ActiveProgressions时的解决方案
如果ActiveProgressions是瞬态服务(每次请求需要新实例),构造函数注入的方式会出现问题:若工厂类是单例,会一直持有同一个瞬态实例,违背其设计意图;若工厂类也是瞬态,虽能解决但并非最优解。以下是几种比给Create()加参数更优的方案:
1. 拆分独立视图创建者(推荐)
遵循单一职责原则,将不同视图的创建逻辑拆分到单独类中,主工厂仅负责分发请求:
// 定义视图创建者通用接口 public interface ICategoryViewCreator { CategoryType TargetType { get; } ICategoryView Create(Category category); } // CategoryView专属创建者 public class CategoryViewCreator : ICategoryViewCreator { public CategoryType TargetType => CategoryType.Category; public ICategoryView Create(Category category) { return new CategoryView(category); } } // SubcategoryView专属创建者,自动注入瞬态ActiveProgressions public class SubcategoryViewCreator : ICategoryViewCreator { private readonly ActiveProgressions _activeProgressions; public SubcategoryViewCreator(ActiveProgressions activeProgressions) { _activeProgressions = activeProgressions; } public CategoryType TargetType => CategoryType.Subcategory; public ICategoryView Create(Category category) { return new SubcategoryView(category, _activeProgressions); } } // 重构后的主工厂 public class CategoryViewFactory : ICategoryViewFactory { private readonly IEnumerable<ICategoryViewCreator> _creators; public CategoryViewFactory(IEnumerable<ICategoryViewCreator> creators) { _creators = creators; } public ICategoryView? Create(CategoryType type, Category category) { var creator = _creators.FirstOrDefault(c => c.TargetType == type); return creator?.Create(category); } }
该方案优势:
- 每个创建者只负责一种视图的创建,职责清晰,后续新增视图只需添加新创建者类,无需修改主工厂(符合开闭原则)。
- 依赖关系完全由DI容器管理,瞬态服务的生命周期自动匹配,不会出现资源泄漏或实例复用错误。
2. 使用服务定位器(简易场景备选)
直接从DI容器中解析瞬态ActiveProgressions实例,适合快速解决简单场景,但需注意避免过度使用(会降低代码的可测试性和透明性):
public class CategoryViewFactory : ICategoryViewFactory { private readonly IServiceProvider _serviceProvider; public CategoryViewFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public ICategoryView? Create(CategoryType type, Category category) { return type switch { CategoryType.Category => new CategoryView(category), CategoryType.Subcategory => new SubcategoryView( category, _serviceProvider.GetRequiredService<ActiveProgressions>()), _ => null }; } }
3. 让视图类由DI容器管理(依赖较多场景适用)
如果ICategoryView的实现类本身有较多依赖,可以让容器负责实例化,通过初始化方法传递category这类运行时参数:
public class CategoryViewFactory : ICategoryViewFactory { private readonly IServiceProvider _serviceProvider; public CategoryViewFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public ICategoryView? Create(CategoryType type, Category category) { return type switch { CategoryType.Category => _serviceProvider.GetRequiredService<CategoryView>().Initialize(category), CategoryType.Subcategory => _serviceProvider.GetRequiredService<SubcategoryView>().Initialize(category), _ => null }; } } // 修改视图类,添加初始化方法 public class CategoryView : ICategoryView { public CategoryView() { } // 无参构造允许容器解析 public ICategoryView Initialize(Category category) { // 处理category初始化逻辑 return this; } } public class SubcategoryView : ICategoryView { private readonly ActiveProgressions _activeProgressions; public SubcategoryView(ActiveProgressions activeProgressions) { _activeProgressions = activeProgressions; } public ICategoryView Initialize(Category category) { // 处理category初始化逻辑 return this; } }
总结
- 单例场景下当前实现完全合规,符合DI设计原则;
- 瞬态场景下,优先选择拆分独立创建者的方案,它的扩展性和可维护性最优;服务定位器适合快速解决简单问题;视图由容器管理的方案适合视图本身依赖复杂的场景。
内容的提问来源于stack exchange,提问作者Dasic
相关产品推荐
相关产品推荐

