这里举一个非常简单的例子,以案例的业务实现来分析如何写好业务代码。
本案例只是简单的模拟,可能与真实的情况有出入,这里只是为了举例使用。
案例:
用户挑选商品放入购物车,然后下单结算,流程如下:
a. 挑选商品 b . 下单 c . 结算 d . 生成订单 e . 通知
提交下单的业务逻辑如下:
a . 验证账号是否合法 b . 调用第三方接口查看商品的打折价格 c . 钱包金额扣除 d . 生成订单信息 e . 通知用户下单成功,等待收货
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private UserMapper userMapper;
@Autowired
private ProductMapper productMapper;
@Autowired
private OrderMapper orderMapper;
@Autowired
private KafkaTemplate kafkaTemplate;
/**
* 购买商品,提交订单
* @param userId 用户ID
* @param productId 商品ID
* @return
*/
public Result submit(Long userId, Long productId) throws BizException {
// 验证账号
UserDO userDO = userMapper.findById(userId);
if (userDO == null) {
throw BizException(USER_NOT_EXISTS);
}
// 查看商品信息及打折信息
ProductDO productDO = productMapper.findById(productId);
Double delta = HttpUtils.getDiscount(productId);
double actualPayment = productDO.getPrice() - delta;
Money money = userDO.getMoney();
if (actualPayment > money.getRemain()) {
// 如果商品价格 - 优惠价格 > 用户钱包,则说明不够付
return Result.fail("余额不足");
}
// 钱包够付,扣除金额
double remain = money.getRemain() - actualPayment;
money.setRemain(remain);
// 更新账号钱包余额
userMapper.update(userDO);
// 生成订单信息
OrderDO orderDO = new OrderDO();
orderDO.setUserId(userId);
orderDO.setProductId(productId);
orderMapper.save(orderDO);
// 通知用户订单已生成,等待收货
kafkaTemplate.send("orderTopic", orderDO);
return Result.ok();
}
}
上面代码写好了,而且可以实现相关功能,但是随着业务的迭代,可能会出现很多问题:
2 . XxDO 是和数据表绑定的,数据表结构变更等也会影响业务代码。
3 . 调用第三方API,直接在业务代码中调用HttpUtils完成,未来第三方API修改了方法签名或返回值,或改为了RPC接口,那么业务代码也会随着改变。
4 . 发送消息直接使用KafkaTemplate,如果技术选型变了要改为使用RocketMQ,那么业务代码还得变。
2 . 业务逻辑和数据存储结构是强依赖的,数据存储结构的变化对业务的影响可想而知;
因为直接依赖了数据库,第三方接口,中间件,所以需要所有技术实现后才能进行测试,测试成本和时间都比较大。
我们上面说了,数据库操作不应该直接暴露在业务逻辑中,因此把数据库操作“隔离”开。
public interface UserRepository {
User findById(Long userId);
}
新增 XxRepository 接口,业务逻辑直接依赖接口/抽象,而不应该直接依赖实现。
Repository 是数据仓库,不一定非得是 DB,也可以是其他的数据操作。
Repository 返回的对象也不是 DO,与数据库结构无关。
DO 对象是只有 set、get 操作,没有其他行为,我们说这有时是一种贫血现象,会导致本该在业务领域实体中完成的事情散落到各个 Service 中,低内聚而且也不好维护。
增加领域实体,相关行为直接在实体内完成(高内聚):
public class Money {
private double remain;
public double getRemain() {
return remain;
}
public void setRemain(double remain) {
this.remain = remain;
}
/**
* 扣费
* @param delta
* @return
*/
public boolean charge(double delta) {
if (remain < delta) {
return false;
}
this.remain -= delta;
return true;
}
}
第三方接口是不可靠的,方法签名或返回值或调用方式都有可能会变的,如果直接在业务中依赖,会对业务造成“腐蚀”,所以应该加一层适配层(也叫防腐层 ACL)。
/**
* 防腐层/适配层
*/
@Service
public class PayServiceImpl implements PayService {
@Autowired
private DiscountFacade discountFacade;
/**
* 支付
* @param money
* @param product
* @return
*/
public boolean pay(Money money, Product product) {
// 获取优惠
Double delta = discountFacade.getDiscount(product.getId());
// 扣除费用
return money.charge(product.getPrice() - delta);
}
}
抽象中间件,不直接依赖具体的 MQ 实现
public interface MessageProducer<T, R> {
Result<R> send(T message);
}
优化后的代码如下:
@Autowired
private UserRepository userRepository;
@Autowired
private ProductRepository productRepository;
@Autowired
private OrderRepository orderRepository;
@Autowired
private MessageProducer<Order,Result> messageProducer;
@Autowired
private PayService payService;
/**
* 购买商品,提交订单
* @param userId 用户ID
* @param productId 商品ID
* @return
*/
public Result submit(Long userId, Long productId) throws BizException {
// 验证
User user = userRepository.findByUserId(userId);
if (user == null) {
throw BizException(USER_NOT_EXISTS);
}
// 支付
Product product = productRepository.findById(productId);
boolean f = payService.pay(user.getMoney(), product);
if (!f) {
return Result.fail("费用扣除失败");
}
// 更新账户
userRepository.update(user);
// 生成订单信息
Order order = OrderFactory.create(user, product);
orderRepository.add(order);
// 通知用户订单已生成,等待收货
messageProducer.send(order);
return Result.ok();
}
代码不一定非常严谨,只是通过这一个简单的例子告诉大家实际工作中代码该怎么写,该遵循哪些目标:
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/UiYApaJIf103mYn_U2bXrQ
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。