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 IStoreProductor an IStoreSubscription(Interface Segregation Principle) 上没有意义。
我考虑过在 中添加ConvertProductToCartItem()和ConvertSubscriptionToCartItem()方法CartHelper,但这似乎违反了单一责任原则。IStoreProduct拥有一个接受s 和IStoreSubscriptions 并进行转换的 CartItemFactory 是否有意义?对于如此简单的转换,这似乎是很多不必要的开销。
我想出的解决方案之一是定义一个显式转换方法:
公共类 StoreProduct : IStoreProduct
{
公共小数价格 { 得到;放; }
公共小数折扣 { 得到;放; }
// ...特性...
公共 ICartItem ToCartItem()
{
// 将调用显式转换实现
返回(CartItem)这个;
}
// 将 Product 显式转换为 CartItem
公共静态显式运算符 CartItem(StoreProduct 产品)
{
返回新的 CartItem()
{
价格 = 产品.价格,
折扣 = 产品.价格,
SalePrice = Helper.CalculateSalePriceForProduct(product),
// ...在此处分配其他适用的属性...
};
}
}
让我将我的GetCartItems方法更改为更简洁的实现:
公共 IEnumerable GetCartItems()
{
返回 Products.Select(p => p.ToCartSummaryItem());
}
但是这种方法的问题在于,这也违反了单一职责原则,因为它与ICartItem类的耦合。我还考虑了一种扩展方法而不是强制转换,但这并没有更好或不同。CartItemStoreProduct
我是否应该让我的具体StoreProduct类实现ICartItem接口并将特定于购物车的属性放在那里?也许我应该重写CartHelper它,使它只有 ICartItems (即删除IProducts)?这两种选择似乎都违反了单一责任原则。也许我睡了一会儿后解决方案会变得很明显......
所以,我想我的问题归结为:在不违反 SOLID 原则的情况下,在接口之间移动数据的最佳方式是什么?
有什么建议么?也许我应该继续前进而不用担心它(即,不要对 SOLID 教条主义)?我回答了我自己的问题吗?也许这属于programmers.stackexchange,我希望这不是太主观。
此外,如果它有帮助,这就是我的界面的样子:
公共接口 IProductBase
{
int ProductID { 获取;放; }
小数价格 { 得到;放; }
字符串标题 { 获取;放; }
字符串描述 { 获取;放; }
// ... 其他属性...
}
公共接口 IStoreProduct : IProductBase
{
int VariantID { 得到;放; }
小数折扣 { 得到;放; }
// ... 其他属性...
ICartItem ToCartItem();
}
公共接口 ISubscription : IProductBase
{
订阅类型订阅类型 { 获取;放; }
// ... 其他属性...
ICartItem ToCartItem();
}
公共接口 ICartItem : IProductBase
{
小数销售价格 { 得到;放; }
// ... 其他属性...
}
更新:为清楚起见添加了帖子属性。