Java8实战-总结48

CompletableFuture:组合式异步编程

对多个异步任务进行流水线操作

实现折扣服务

你的“最佳价格查询器”应用现在能从不同的商店取得商品价格,解析结果字符串,针对每个字符串,查询折扣服务取的折扣代码。这个流程决定了请求商品的最终折扣价格(每个折扣代码的实际折扣比率有可能发生变化,所以你每次都需要查询折扣服务)。我们已经将对商店返回字符串的解析操作封装到了下面的Quote类之中:

public class Quote { 

	private final String shopName; 
	private final double price; 
	private final Discount.Code discountCode; 
	
	public Quote(String shopName, double price, Discount.Code code) { 
		this.shopName = shopName;
		this.price = price; 
		this.discountCode = code; 
	} 
	public static Quote parse(String s) { 
	 	String[] split = s.split(":"); 
	 	String shopName = split[0];
	 	double price = Double.parseDouble(split[1]);
	 	Discount.Code discountCode = Discount.Code.valueOf(split[2]); 
	 		return new Quote(shopName, price, discountCode); 
	} 
	
	public String getShopName() { return shopName; } 
	public double getPrice() { return price; } 
	public Discount.Code getDiscountCode() { return discountCode; } 
} 

通过传递shop对象返回的字符串给静态工厂方法parse,可以得到Quote类的一个实例,它包含了shop的名称、折扣之前的价格,以及折扣代码。Discount服务还提供了一个applyDiscount方法,它接收一个Quote对象,返回一个字符串,表示生成该Quoteshop中的折扣价格,代码如下所示。

public class Discount { 
	public enum Code { 
 		// 源码暂时省略……
	} 
	
	public static String applyDiscount(Quote quote) {
		return quote.getShopName() + " price is " + 
				Discount.apply(quote.getPrice(), 
							   quote.getDiscountCode()); 
	} 
	
	private static double apply(double price, Code code) { 
		delay(); 
		return format(price * (100 - code.percentage) / 100);
	} 
} 

使用 Discount 服务

由于Discount服务是一种远程服务,你还需要增加1秒钟的模拟延迟,代码如下所示。首先尝试以最直接的方式(坏消息是,这种方式是顺序而且同步执行的)重新实现findPrices,以满足这些新增的需求。
代码清单11-15 以最简单的方式实现使用Discount服务的findPrices方法

public List<String> findPrices(String product) {
	return shops.stream()
				.map(shop -> shop.getPrice(product)) //取得每个shop对象中商品的原始价格
				.map(Quote::parse) //在Quote对象中对shop返回的字符串进行转换
				.map(Discount::applyDiscount) //联系Discount服务,为每个Quote申请折扣
				.collect(toList()); 
}

通过在shop构成的流上采用流水线方式执行三次map操作,我们得到了期望的结果。

  • 第一个操作将每个shop对象转换成了一个字符串,该字符串包含了该 shop中指定商品的价格和折扣代码。
  • 第二个操作对这些字符串进行了解析,在Quote对象中对它们进行转换。
  • 最终,第三个map会操作联系远程的Discount服务,计算出最终的折扣价格,并返回该价格及提供该价格商品的shop

这种实现方式的性能远非最优,不过还是应该测量一下。跟之前一样,通过运行基准测试,得到下面的数据:

[BestPrice price is 110.93, LetsSaveBig price is 135.58, MyFavoriteShop price 
 is 192.72, BuyItAll price is 184.74, ShopEasy price is 167.28] 
Done in 10028 msecs 

毫无意外,这次执行耗时10秒,因为顺序查询5个商店耗时大约5秒,现在又加上了Discount服务为5个商店返回的价格申请折扣所消耗的5秒钟。你已经知道,把流转换为并行流的方式,非常容易提升该程序的性能。不过,这一方案在商店的数目增加时,扩展性不好,因为Stream底层依赖的是线程数量固定的通用线程池。相反,如果自定义CompletableFutures调度任务执行的执行器能够更充分地利用CPU资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值