当前位置:编程学堂 > 摆脱“重复代码”,这三种方法完美!

摆脱“重复代码”,这三种方法完美!

  • 发布:2023-10-07 13:03

点击关注公众号,实用技术文章随时了解

软件工程师和码农最大的区别就是他们写代码的习惯。码农喜欢写重复的代码,而软件工程师则会用各种技巧去掉重复、冗余的代码。

商科同学抱怨业务开发没有技术含量,不使用设计模式,java高级特性,OOP,平时写代码有大量CRUD,无从谈起个人成长。

其实我不这么认为。设计模式和OOP是前辈在大型项目中积累的经验。这些方法用于提高大型项目的可维护性。反射、注解、泛型等高级特性之所以在框架中被广泛使用,是因为框架往往需要使用同一套算法来处理不同的数据结构,而这些特性可以帮助减少代码的重复,提高项目的可维护性。

在我看来,可维护性是大型项目成熟度的重要指标,而提高可维护性的一个非常重要的方法就是减少代码重复。那么为什么这么说呢?

  • 如果多处重复代码实现同一个功能,很容易修改一处而忘记修改另一处,造成Bug

  • 有些代码并不完全重复,但非常相似。修改这些相似的代码,将原来的差异变成相同,很容易出错(复制粘贴)。

今天就从业务代码中最常见的三个需求开始,讲一下如何利用Java中的一些高级特性、设计模式以及一些工具来消除重复代码,从而能够既优雅又优雅高端。通过今天的学习,也希望能改变大家认为业务代码没有技术含量的看法。

1。使用工厂模式+模板方法模式消除if…else和重复代码

假设你要开发一个购物车下单功能,针对不同的用户进行不同的处理:

  • 普通用户需要支付运费,运费为产品价格的10%,无产品折扣;

  • VIP用户还需收取产品价格10%的快递费,但购买两件及以上相同产品时,第三件将享受一定折扣;

  • 内部用户可享受免运费且无产品折扣。

我们的目标是实现三种类型的购物车业务逻辑,并将输入参数Map对象(Key为商品ID,Value为商品数量)转换为输出购物车类型Cart。

首先实现普通用户的购物车处理逻辑:

//购物车 
@Data
public class购物车 {
//产品列表
私有列表项目=ArrayList<> ();
//总折扣
private BigDecimal TotalDiscount;
//商品总价
private BigDecimaltotalItemPrice; //总运费
private BigDecimaltotalDeliveryPrice;
//应付总价
private BigDecimal payPrice;
}
//购物车中的商品
@Data
public class 项目 {
//产品ID

private long id;
//商品数量
私人 int数量;
//商品单价
private BigDecimal 价格;
//产品折扣
私人 BigDecimal couponPrice;
//商品运费
私人大十进制送货价格;
}
//普通用户购物车处理
public class NormalUserCart {
公共购物车进程long用户ID,地图项目) {
购物车 cart = new Cart();

//将Map购物车转换为Item列表
  List itemList = new ArrayList<>();
items.entrySet().stream().forEach(entry -> {
Item item = new Item();
Item.setId(entry.getKey()) ;
Item.setPrice(Db.getItemPrice(entry.getKey() )));
.getValue());
                                                                                                                                                                                              
//处理运输和产品折扣
www.sychzs.cn().forEach(item -> {
item.getPrice().multiply(BigDecimal.valueOf(item. getQuantity())).multiply(new BigDecimal("0.1")));
            });   cart.setTotalItemPrice(cart.getItems().stream().map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity()))).reduce(www.sychzs.cn, BigDecimal: ; ERO,BigDecimal: ; BigDecimal:: 添加));
//应付总价=商品总价+运费总价-折扣总额
                                                                                                                                                                                         ( cart.getTotalDiscount()));
返回购物车;

然后实现VIP用户的购物车逻辑。与普通用户的购物车逻辑不同的是,VIP用户购买更多同款商品可以享受折扣。所以这部分代码只需要对多买折扣部分进行额外处理:

公共VipUserCart{(...  

www.sychzs.cn().forEach(item - > { 为费 // 商品总价的10%
Item.setDeliveryPrice(item.getprice().Multiply(bigdecimal.Valueof(item.getQuality())).BigDecimal(" 0.1")));
if (item .getQuantity() > 2) {
                                                                                                                            。(BigDecimal.value) Of(100 - Db.getUserCouponPercent(userId) ).divide(new BigDecimal("100")))
 - 2)));
                               {
}
});


返回购物车;
}
}

最后,免运费,没有折扣的内部用户在处理产品折扣和运费时也只是逻辑上的区别:

公共 InternalUserCart{(...  
                                                                                                    ​               item.setCouponPrice(www.sychzs.cn);                                                                                                                                          . ..
返回购物车; }

对比代码量可以发现,三个购物车中有70%的代码是重复的。原因很简单。虽然不同类型的用户计算运费和折扣的方式不同,但初始化整个购物车、统计总价、总运费、总折扣和支付价格的逻辑是相同的。

正如我们一开始提到的,代码重复本身并不可怕,可怕的是遗漏或出错。比如,有同学写了一个VIP用户购物车,发现商品总价的计算有bug。不要将所有商品的价格加在一起,而应将所有商品的价格*数量加在一起。

这个时候他可能只会修改VIP用户购物车的代码,而忽略普通用户和内部用户购物车中同样的bug。

我们有了三个购物车后,我们需要根据不同的用户类型使用不同的购物车。如下代码所示,通过三个if来实现不同类型用户调用不同购物车的处理方法:

@GetMapping“错误”
公共购物车错误 (@RequestParam("用户ID")int userId) {
userCategory = Db.getUserCategory(userId);
//普通用户处理逻辑
if (userCategory.equals("普通" )) {
NormalUserCart normalUserCart = NormalUserCart();
返回 normalUserCart.process(userId, items);
}
//VIP用户处理逻辑
if (userCategory.equals() “VIP”
)) {
                VipUserCart   vipUserCart =   newVipUserCart();
返回 vipUserCart.process(userId, items);
}
//内部用户处理逻辑
if (userCategory.equals() “内部”)) {
          InternalUserCart 内部用户购物车 = InternalUserCart();
返回internalUserCart.process(使用rId,项目);
}

返回 null;
}

电商营销方式多种多样。未来必然会有更多的用户类型,需要更多的购物车。我们是否可以继续添加更多的购物车类,编写重复的购物车逻辑,并一遍又一遍地编写更多的 if 逻辑?

当然不是,相同的代码只能出现在一个地方!

如果我们记住了抽象类和抽象方法的定义,这个时候我们可能会想,是否可以在抽象类中定义重复的逻辑,让三个购物车只需要实现不同的逻辑呢?

其实这个模式就是模板方法模式。我们在父类中实现了购物车处理流程模板,然后将需要特殊处理的区域留空,即留下抽象方法定义,让子类实现逻辑。由于父类的逻辑不完整,无法单独工作,因此需要将其定义为抽象类。

如下代码所示,AbstractCart抽象类实现了购物车的通用逻辑,并额外定义了两个抽象方法供子类实现。其中,processCouponPrice方法用于计算产品折扣,processDeliveryPrice方法用于计算运费。

公共抽象AbstractCart   { 
//处理购物的大量重复逻辑cart 在父类中 Implement
public Cart process(long userId, Map 项) {

= 购物车();
ArrayList<>();
items.entrySet().stream() .forEach(entry -> {
Item item = new Item();
Item.setId (entry.getKey()) ;
                                                                                     .getKey()); ;
Cart.setItems(itemList);
//让子类处理每件商品的折扣
                                                                                                                                                                                                                                  processDeliveryPrice(userId, item); });
//计算商品总价
cart.setTotalItemPrice(cart.getItems().stream().map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity()))).reduce(www.sychzs.cn, BigDecimal::add );); ;
//计算应付价格
cart.setPayPrice(cart.getTotalItemPrice().add(cart.getTotalDeliveryPrice()).subtract(cart.getTotalDiscount())); 返回 购物车;
}

受保护 抽象 void processCouponPrice(long userId, Item item ); //处理运费的逻辑留给子类实现
protected abstract void 流程发货价格(用户ID,物品项目);
}

有了这个抽象类,三个子类的实现就非常简单了。普通用户的购物车NormalUserCart实现0折扣10%运费的逻辑:

@Service(值 = “NormalUserCart”
公共 NormalUserCart 扩展 AbstractCart {


受保护 void 处理优惠券价格long userId , 商品商品) {
  item.setCouponPrice(www.sychzs.cn);
}

@Override
受保护 void 处理发货价格) userId, 商品商品) {
item.setDeliveryPrice(item .getPrice()
.multiply(BigDecimal.valueOf(item.getQuantity())) .乘( BigDecimal("0.1")));
}
}

VIP用户的购物车VipUserCart,直接继承NormalUserCart,只需修改多买折扣策略:

@服务(值 = “VipUserCart”
公共 VipUserCart 延伸 NormalUserCart {


受保护 void processCouponPrice( Slong userid, item item) {
IF (item.getquantity ()> 2) {
ivem.setCouponprice (item.getprice ( )
.multiply(BigDecimal.valueOf( 100 - Db.getUserCouponPercent(userId)).divide(new BigDe cimal("100")))
.multiply(BigDecimal.valueOf(item.getQuantity( ) - 2)));
} else {
Item.setCouponPrice(www.sychzs.cn);
}
}
}

内部用户购物车InternalUserCart最简单,只需设置0运费和0折扣:

@Service(值= “InternalUserCart”)  
公共 类  InternalUserCart 扩展 AbstractCart {  
    @Override  
    受保护 void 处理优惠券价格长)  用户 ID, 商品 商品) {  
        item.setCouponPrice(www.sychzs.cn);
    }  
  
    @Override  
    受保护 void 流程交货价格) userId, Item item) {  
        item.setDeliveryPrice(www.sychzs.cn);
    }  
}  

抽象类和三个子类的实现关系图,如下所示:

来源:我是程序汪

推荐

Java面试题宝典

技术内卷群,一起来学习!!

PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。“在看”支持我们吧!

相关文章

热门推荐