TL;DR:在不违反 SOLID 原则的情况下,在接口之间移动数据的最佳方式是什么?
我可能想多了,我不打算在 SOLID 原则方面教条;但我想得到一些意见。我一直在将购物车重构为更加“可靠”,并且我编写的一种方法对我来说似乎是“代码味道”(也许不是)。
我有一个CartHelper
看起来像这样的类(为简洁起见,我对其进行了一些简化):
公共类 CartHelper { IEnumerable 产品; IEnumerable 订阅; // ...其他类方法... [HttpPost] 公共无效 AddItem(int productVariantID) { var product = ProductService.GetByVariantID(productVariantID); 如果(产品!= null) { if (product.Type == (int)Constants.ProductTypes.Subscription) 订阅 = Subscriptions.Concat(new [] { product }); Products = Products.Concat(new [] { product }); CartService.AddItem(productVariantID); } } [HttpPost] public void RemoveItem(int productVariantID) { Subscriptions = Subscriptions.Where(s => s.VariantID != productVariantID); Products = Products.Where(p => p.VariantID != productVariantID); CartService.RemoveItem(productVariantID); } 公共小数 GetCartTotalBeforeDiscount() { 返回 Products.Sum(p => p.Price); } 公共 IEnumerable GetCartItems() { var products =(来自 Products 中的 p 选择新的 CartSummaryItem { ProductID = p.ProductID, 标题 = p.标题, 描述 = p.描述, 价格 = p.Price, // ...在此处分配其他适用的属性... } 作为 ICartSummaryItem); 退货; } // ...其他类方法... }
对我来说似乎是“代码气味”的部分(这里可能还有更多不好的部分)是GetCartItems()
方法。关于它的某些东西对我来说似乎很时髦,但我想不出更好的替代方案。
我正在转换为,ICartItem
因为添加了一些需要传递给视图的属性,但它们在 an IStoreProduct
or an IStoreSubscription
(Interface Segregation Principle) 上没有意义。
我考虑过在 中添加ConvertProductToCartItem()
和ConvertSubscriptionToCartItem()
方法CartHelper
,但这似乎违反了单一责任原则。IStoreProduct
拥有一个接受s 和IStoreSubscription
s 并进行转换的 CartItemFactory 是否有意义?对于如此简单的转换,这似乎是很多不必要的开销。
我想出的解决方案之一是定义一个显式转换方法:
公共类 StoreProduct : IStoreProduct { 公共小数价格 { 得到;放; } 公共小数折扣 { 得到;放; } // ...特性... 公共 ICartItem ToCartItem() { // 将调用显式转换实现 返回(CartItem)这个; } // 将 Product 显式转换为 CartItem 公共静态显式运算符 CartItem(StoreProduct 产品) { 返回新的 CartItem() { 价格 = 产品.价格, 折扣 = 产品.价格, SalePrice = Helper.CalculateSalePriceForProduct(product), // ...在此处分配其他适用的属性... }; } }
让我将我的GetCartItems
方法更改为更简洁的实现:
公共 IEnumerable GetCartItems() { 返回 Products.Select(p => p.ToCartSummaryItem()); }
但是这种方法的问题在于,这也违反了单一职责原则,因为它与ICartItem
类的耦合。我还考虑了一种扩展方法而不是强制转换,但这并没有更好或不同。CartItem
StoreProduct
我是否应该让我的具体StoreProduct
类实现ICartItem
接口并将特定于购物车的属性放在那里?也许我应该重写CartHelper
它,使它只有 ICartItems (即删除IProduct
s)?这两种选择似乎都违反了单一责任原则。也许我睡了一会儿后解决方案会变得很明显......
所以,我想我的问题归结为:在不违反 SOLID 原则的情况下,在接口之间移动数据的最佳方式是什么?
有什么建议么?也许我应该继续前进而不用担心它(即,不要对 SOLID 教条主义)?我回答了我自己的问题吗?也许这属于programmers.stackexchange,我希望这不是太主观。
此外,如果它有帮助,这就是我的界面的样子:
公共接口 IProductBase { int ProductID { 获取;放; } 小数价格 { 得到;放; } 字符串标题 { 获取;放; } 字符串描述 { 获取;放; } // ... 其他属性... } 公共接口 IStoreProduct : IProductBase { int VariantID { 得到;放; } 小数折扣 { 得到;放; } // ... 其他属性... ICartItem ToCartItem(); } 公共接口 ISubscription : IProductBase { 订阅类型订阅类型 { 获取;放; } // ... 其他属性... ICartItem ToCartItem(); } 公共接口 ICartItem : IProductBase { 小数销售价格 { 得到;放; } // ... 其他属性... }
更新:为清楚起见添加了帖子属性。