TL;DR: SOLID の原則に違反せずにインターフェイス間でデータを移動する最善の方法は何ですか?
私はこれを考えすぎているかもしれませんが、SOLID の原則に関して独断的になるつもりはありません。しかし、私はいくつかのインプットを得たかったのです。私はショッピングカートをより「しっかり」するようにリファクタリングしてきましたが、私が書いたメソッドは「コードの匂い」のように思えます (そうではないかもしれません)。
次のようなCartHelper
クラスがあります (簡潔にするために少し簡略化しています)。
パブリック クラス CartHelper { IEnumerable Products; IEnumerable サブスクリプション。 // ...その他のクラスメソッド... [HttpPost] public void AddItem(int productVariantID) { var product = ProductService.GetByVariantID(productVariantID); if (製品 != null) { if (product.Type == (int)Constants.ProductTypes.Subscription) Subscriptions = Subscriptions.Concat(new [] { product }); Products = Products.Concat(new [] { product }); CartService.AddItem(productVariantID); } } [HttpPost] public void RemoveItem(int productVariantID) { サブスクリプション = Subscriptions.Where(s => s.VariantID != productVariantID); Products = Products.Where(p => p.VariantID != productVariantID); CartService.RemoveItem(productVariantID); } 公開小数 GetCartTotalBeforeDiscount() { Products.Sum(p => p.Price) を返します。 } public IEnumerable GetCartItems() { var products = (Products の p から 新しい CartSummaryItem を選択 { ProductID = p.ProductID、 タイトル = p.タイトル、 説明 = p.説明、 価格 = p.価格、 // ...他の適用可能なプロパティをここに割り当てます... } ICartSummaryItem として); 製品を返品します。 } // ...その他のクラスメソッド... }
私にとって「コード臭」のように見える部分 (そして、ここにはもっと悪い部分があるかもしれません) はGetCartItems()
メソッドです。それについての何かが私にはファンキーに思えますが、それ以上の代替案は思いつきません.
ビューに渡す必要があるいくつかのプロパティが追加されていますが、または(インターフェイス分離の原則) ではICartItem
意味がありません。IStoreProduct
IStoreSubscription
ConvertProductToCartItem()
にとConvertSubscriptionToCartItem()
メソッドを追加することを考えましたCartHelper
が、それは単一責任の原則に違反しているようです。IStoreProduct
s とsを受け入れて変換する CartItemFactory を持つことは理にかなっていIStoreSubscription
ますか? このような単純な変換には、多くの不必要なオーバーヘッドがかかるようです。
私が思いついた解決策の 1 つは、明示的なキャスト メソッドを定義することです。
パブリック クラス StoreProduct : IStoreProduct { 公開小数価格{取得; 設定; } public decimal 割引 { get; 設定; } // ...プロパティ... public ICartItem ToCartItem() { // 明示的なキャスト実装を呼び出します return (CartItem) this; } // Product を CartItem として明示的にキャスト変換する public static explicit operator CartItem(StoreProduct 商品) { new CartItem() を返す { 価格 = 商品.価格、 割引 = 商品.価格、 SalePrice = Helper.CalculateSalePriceForProduct(製品)、 // ...他の適用可能なプロパティをここに割り当てます... }; } }
これにより、GetCartItems
メソッドをこのよりクリーンな実装に変更できます。
public IEnumerable GetCartItems() { 製品を返します。選択 (p => p.ToCartSummaryItem()); }
しかし、このアプローチの問題は、クラスへのカップリングICartItem
によって単一責任の原則にも違反することです。キャスト変換の代わりに拡張メソッドも検討しましたが、それは優れているわけでも違いがあるわけでもありません。CartItem
StoreProduct
具象StoreProduct
クラスにインターフェイスを実装させ、ICartItem
そこにカート固有のプロパティを配置する必要がありますか? CartHelper
ICartItems のみを持つように (つまり、s を削除して) を書き直すべきIProduct
でしょうか? これらのオプションは両方とも、単一責任の原則に違反しているように見えます。たぶん、私が少し寝た後に解決策が明らかになるでしょう...
要するに、私の質問は、SOLID の原則に違反することなくインターフェース間でデータを移動する最善の方法は何かということだと思います。
助言がありますか?たぶん、私はそれについて心配する必要はありません (つまり、SOLID について独断的にならないでください)。私は自分の質問に答えましたか?これはプログラマー.stackexchange に属している可能性があります。主観的すぎないことを願っています。
また、役に立つ場合は、これが私のインターフェイスの外観です。
パブリック インターフェイス IProductBase { int ProductID { get; 設定; } 10 進価格 { get; 設定; } 文字列のタイトル { get; 設定; } 文字列 説明 { get; 設定; } // ... その他のプロパティ... } パブリック インターフェイス IStoreProduct : IProductBase { int バリアント ID { get; 設定; } 小数の割引{取得; 設定; } // ... その他のプロパティ... ICartItem ToCartItem(); } パブリック インターフェイス ISubscription : IProductBase { SubscriptionType SubscriptionType { get; 設定; } // ... その他のプロパティ... ICartItem ToCartItem(); } パブリック インターフェイス ICartItem : IProductBase { 10進数のSalePrice {get; 設定; } // ... その他のプロパティ... }
更新:わかりやすくするために投稿属性を追加しました。