Stream流收集器的購物車DDD聚合真實示例 - foojay
Java Stream的Collectors方法適合大多數用例。它們允許返回aCollection或標量。對於前者,使用一種toXXX()方法,對於後者,使用一種方法reducing()。
讓我們想象一個實現購物車的電子商務平臺。該購物車的建模如下:
這非常類似DDD設計中聚合,Cart作為一個聚合根實體。
public class Product { private final Long id; // 1 private final String label; // 1 private final BigDecimal price; // 1 public Product(Long id, String label, BigDecimal price) { this.id = id; this.label = label; this.price = price; } @Override public boolean equals(Object object ) { ... } // 2 @Override public int hashCode() { ... } // 2 } public class Cart { private final Map<Product, Integer> products = new HashMap<>(); // 1 public void add(Product product) { add(product, 1); } public void add(Product product, int quantity) { products.merge(product, quantity, Integer::sum); } public void remove(Product product) { products.remove(product); } public void setQuantity(Product product, int quantity) { products.put(product, quantity); } public Map<Product, Integer> getProducts() { return Collections.unmodifiableMap(products); // 2 } } |
定義瞭如何在記憶體中儲存資料後,我們需要設計如何在螢幕上顯示購物車。我們知道,結帳螢幕需要顯示兩個不同的資訊位:
- 行的列表,其中每一行的價格,即每種產品的價格乘以數量。
- 購物車的整體價格。
相應程式碼:
public record CartRow(Product product, int quantity) { // 1 public CartRow(Map.Entry<Product, Integer> entry) { this(entry.getKey(), entry.getValue()); } public BigDecimal getRowPrice() { return product.getPrice().multiply(new BigDecimal(quantity)); } } var rows = cart.getProducts() .entrySet() .stream() .map(CartRow::new) .collect(Collectors.toList()); // 1 var price = cart.getProducts() .entrySet() .stream() .map(CartRow::new) .map(CartRow::getRowPrice) // 2 .reduce(BigDecimal.ZERO, BigDecimal::add); // 3 |
Java流的主要限制之一是隻能使用一次。原因是流物件不一定是不變的(儘管它們可以是不變的)。因此,兩次執行相同的流可能不是冪等的。
因此,要獲取行和價格,我們需要從購物車建立兩個流。從一個流中,我們將獲得行,而從另一流中,將獲得價格。
如果我們想從單個流中收集行和價格。我們需要一個可Collector在一次透過中將兩個物件都作為單個物件返回的自定義。
public class PriceAndRows { private BigDecimal price; // 1 private final List<CartRow> rows = new ArrayList<>(); // 2 PriceAndRows(BigDecimal price, List<CartRow> rows) { this.price = price; this.rows.addAll(rows); } PriceAndRows() { this(BigDecimal.ZERO, new ArrayList<>()); } } |
這是Collector介面的摘要。有關更多詳細資訊,請檢查此以前的帖子。
- supplier() 提供基礎物件以開始
- accumulator() 描述如何將當前流式專案累積到容器中
- combiner() 如果流是並行的,請描述如何合併它們
- finisher() 如果可變容器型別不是返回的型別,請描述如何將前者轉換為後者
- characteristics() 提供後設資料以最佳化流
鑑於此,我們可以相應地實現Collector:
private static class PriceAndRowsCollector implements Collector<Map.Entry<Product, Integer>, PriceAndRows, PriceAndRows> { @Override public Supplier<PriceAndRows> supplier() { return PriceAndRows::new; // 1 } @Override public BiConsumer<PriceAndRows, Map.Entry<Product, Integer>> accumulator() { return (priceAndRows, entry) -> { // 2 var row = new CartRow(entry); priceAndRows.price = priceAndRows.price.add(row.getRowPrice()); priceAndRows.rows.add(row); }; } @Override public BinaryOperator<PriceAndRows> combiner() { return (c1, c2) -> { // 3 c1.price = c1.price.add(c2.price); var rows = new ArrayList<>(c1.rows); rows.addAll(c2.rows); return new PriceAndRows(c1.price, rows); }; } @Override public Function<PriceAndRows, PriceAndRows> finisher() { return Function.identity(); // 4 } @Override public Set<Characteristics> characteristics() { return Set.of(Characteristics.IDENTITY_FINISH); // 4 } } |
設計Collector涉及一些工作,但是使用自定義收集器很容易:
var priceAndRows = cart.getProducts() .entrySet() .stream() .collect(new PriceAndRowsCollector()); |
您可以使用Collectors該類中提供的即用型收集器來解決大多數用例。但是,有些需要實現自定義Collector,例如,當您需要收集多個單個集合或單個標量時,則需要實現一個custom 。
如果您以前從未開發過它,可能看起來很複雜,但事實並非如此。您只需要一點練習即可。希望這篇文章對您有所幫助。
您可以在GitHub上以Maven格式找到此帖子的原始碼。
相關文章
- 購物車的實現原理
- 購物車原理以及實現
- Vue實現購物車效果Vue
- Vue實現簡單的購物車功能Vue
- Android實現商城購物車功能Android
- 【jquery】實現購物車加減jQuery
- jQuery實現購物車的增刪改查jQuery
- 我的Vue之旅 11 Vuex 實現購物車Vue
- 使用Spring Data JDBC實現DDD聚合SpringJDBC
- 加入購物車動畫效果實現動畫
- vue2.0實現購物車功能Vue
- 原生js實現購物車結算JS
- DDD之4聚合和聚合根
- Nodejs 實踐 -- Stream 流NodeJS
- day83:luffy:新增購物車&導航欄購物車數字顯示&購物車頁面展示
- flutter 購物車功能Flutter
- 購物車模組
- ATM+購物車
- DDD中聚合、聚合根的含義以及作用
- Java Stream過濾器案例解說 - FoojayJava過濾器
- 淘寶買家授權API系列:新增購物車商品、刪除購物車商品、獲取購物車商品列表API
- Stream聚合函式函式
- python之購物車程式Python
- 用Provider實現商品加入購物車的動畫效果IDE動畫
- 自學Vue的第06天:實戰之購物車Vue
- 使用Spring Data JPA實現DDD聚合的動態投影Spring
- 網站購物車介面(div+css實現)網站CSS
- Stream流
- 微信小程式的購物車功能微信小程式
- DDD聚合的數學模型 -Thomas Ploch模型
- jQuery 加入購物車 彈窗jQuery
- vue例項-購物車功能Vue
- DDD聚合設計原則
- node中的流(stream)
- Stream流求和
- 使用Vue做一個購物車Vue
- python-購物車程式練習Python
- 購物車(OK HTTP方法請求)HTTP