C#抽象工厂模式问题:无法访问具体类自有方法
问题描述
我正在学习C#设计模式,朋友帮我写了一套抽象工厂模式的代码。逻辑是先创建工厂Fa,Fa根据枚举创建工厂Fb,再由Fb生成可调用API的具体类。但我发现通过Fb创建的对象只能调用父接口IDoll的方法,访问不了自身(比如IJaneDoll)的自有方法。我需要创建Jane Doll这类继承自Doll且有自有属性的对象,后续如果加Santa Doll也要能访问它的专属方法,该怎么解决?
Web.Controllers
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Qqq.Dolls.Web.Controllers { public class InventoryController : Controller { private readonly IDollFactory _dollFactory; private readonly IJaneDollFactory _janeDollFactory; private readonly IMapper _mapper; public InventoryController(IJaneDollFactory dollFactory, IMapper mapper, IDollFactory dollFactory1) { _janeDollFactory = dollFactory; _mapper = mapper; _dollFactory = dollFactory1; } public async Task<IActionResult> List() { var token = HttpContext.Session.GetObject<OAuthResponse>(SessionConstants.JaneToken); var doll = _JaneDollFactory.Create(token, JaneScopeConstants.GetAllScopes()); var a = _DollFactory.Create(Doll.Jane, HttpContext); var ab = await a.LGetProductAsync("TestProduct"); var inventory = await doll.GetInventory(); var ret = inventory.InventoryItems.Select( inventoryItem => _mapper.Map<InventoryViewModel>(inventoryItem)); return View(ret); } } }
DollFactory
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Qqq.Dolls.Web.Infrastructure; public class DollFactory : IDollFactory { private readonly IJaneDollFactory _JaneDollFactory; public DollFactory(IJaneDollFactory JaneDollFactory) { _JaneDollFactory = JaneDollFactory; } public IDoll Create(Doll Doll, HttpContext httpContext) { switch (Doll) { case Doll.Jane: var token = httpContext.Session.GetObject<OAuthResponse>(SessionConstants.JaneToken); return _JaneDollFactory.Create(token, JaneScopeConstants.GetAllScopes()); default: throw new NotImplementedException(); } } }
IJaneDollFactory Interface
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Qqq.Dolls.Jane; public interface IJaneDollFactory { IJaneDoll Create(OAuthResponse oAuthResponse, List<string> scopes, HttpMessageHandler httpMessageHandler = null); }
IJaneDoll interface
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Qqq.Dolls.Jane; public interface IJaneDoll : IDoll { //Inventory Task<Inventory> GetInventory(); Task ListInventoryItem(InventoryItem product); Task DeleteInventoryItem(string sku); }
IDoll interface
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; public interface IDoll { Task ListProductAsync(Product product); Task<Product> GetProductAsync(string productId); }
IDollFactory
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Qqq.Dolls.Web.Infrastructure; public interface IDollFactory { IDoll Create(Doll doll, HttpContext httpContext); }
JaneDollFactory
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Qqq.Dolls.Jane; public class JaneDollFactory : IJaneDollFactory { private readonly IMapper _mapper; private readonly JaneApiConfiguration _JaneApiConfiguration; public JaneDollFactory(IOptions<JaneApiConfiguration> JaneApiConfiguration, IMapper mapper) { _mapper = mapper; _JaneApiConfiguration = JaneApiConfiguration.Value; } public IJaneDoll Create(OAuthResponse oAuthResponse, List<string> scopes, HttpMessageHandler httpMessageHandler = null) { return new JaneDoll(_mapper, _JaneApiConfiguration, oAuthResponse, scopes, httpMessageHandler); } }
解决方案
针对这个问题,有几种实用的处理方式,可根据后续扩展需求选择:
方式一:泛型工厂接口改造(推荐)
把顶层IDollFactory改成泛型接口,让工厂直接返回具体子类型,保证类型安全且支持扩展:
1. 修改IDollFactory为泛型
namespace Qqq.Dolls.Web.Infrastructure; public interface IDollFactory<TDoll> where TDoll : IDoll { TDoll Create(Doll dollType, HttpContext httpContext); }
2. 实现泛型DollFactory
public class DollFactory<TDoll> : IDollFactory<TDoll> where TDoll : IDoll { private readonly IJaneDollFactory _janeDollFactory; // 后续添加SantaDollFactory依赖 public DollFactory(IJaneDollFactory janeDollFactory) { _janeDollFactory = janeDollFactory; } public TDoll Create(Doll dollType, HttpContext httpContext) { switch (dollType) { case Doll.Jane: var token = httpContext.Session.GetObject<OAuthResponse>(SessionConstants.JaneToken); return (TDoll)(object)_janeDollFactory.Create(token, JaneScopeConstants.GetAllScopes()); case Doll.Santa: // 调用SantaDollFactory创建对象并转换类型 break; default: throw new NotImplementedException(); } } }
3. 控制器中使用泛型工厂
public class InventoryController : Controller { private readonly IDollFactory<IJaneDoll> _janeDollFactory; private readonly IMapper _mapper; public InventoryController(IDollFactory<IJaneDoll> janeDollFactory, IMapper mapper) { _janeDollFactory = janeDollFactory; _mapper = mapper; } public async Task<IActionResult> List() { var janeDoll = _janeDollFactory.Create(Doll.Jane, HttpContext); // 直接调用IJaneDoll专属方法 var inventory = await janeDoll.GetInventory(); var ret = inventory.InventoryItems.Select( inventoryItem => _mapper.Map<InventoryViewModel>(inventoryItem)); return View(ret); } }
方式二:类型转换(快速临时解决)
如果不想改动工厂结构,可在获取对象后做类型判断和转换,缺点是需要提前知晓具体类型:
var doll = _dollFactory.Create(Doll.Jane, HttpContext); if (doll is IJaneDoll janeDoll) { var inventory = await janeDoll.GetInventory(); // 处理业务逻辑 }
方式三:访问者模式(复杂场景适配)
如果后续Doll类型多、专属操作差异大,可用访问者模式统一处理不同类型的专属逻辑:
1. 定义访问者接口
public interface IDollVisitor { void Visit(IJaneDoll janeDoll); void Visit(ISantaDoll santaDoll); }
2. 扩展IDoll接口添加Accept方法
public interface IDoll { Task ListProductAsync(Product product); Task<Product> GetProductAsync(string productId); void Accept(IDollVisitor visitor); }
3. 实现具体Doll的Accept方法
public class JaneDoll : IJaneDoll { // 原有方法实现... public void Accept(IDollVisitor visitor) { visitor.Visit(this); } }
4. 创建具体访问者处理逻辑
public class InventoryVisitor : IDollVisitor { public async Task<Inventory> Inventory { get; private set; } public void Visit(IJaneDoll janeDoll) { Inventory = await janeDoll.GetInventory(); } public void Visit(ISantaDoll santaDoll) { // 处理SantaDoll专属逻辑 } }
5. 控制器中使用
var visitor = new InventoryVisitor(); var doll = _dollFactory.Create(Doll.Jane, HttpContext); doll.Accept(visitor); var inventory = visitor.Inventory;
内容的提问来源于stack exchange,提问作者Clas Antics
相关产品推荐
相关产品推荐

