六、如何解决循环依赖

一、spring 概述
二、XML配置spring容器
三、Spring依赖注入类型
四、Spring依赖注入原理分析
五、Spring循环依赖解决方案
六、如何解决循环依赖


如何解决循环依赖

在日常的开发中,可能我们都会遇到循环依赖的问题。假设有一个商城,里面有用户Account和订单Order两个类。每个用户都有很多订单,用户购买时打折力度和订单的数量成反比。用户Account和订单Order之间的关联关系和代码如下。

查看关联关系以及代码,很明显它们之间构成相互依赖关系。那么,该如何消除循环依赖关系呢?当我们碰到问题无从下手时,不妨考虑一下是否可以通过“加一层”的方法进行解决。消除循环依赖的基本思路也是这样,通过在两个相互循环依赖的组件之间添加中间层,将循环依赖转变为间接依赖。有三种方法可以做到这一点,分别是提取中介者转移业务逻辑引入回调

代码清单1-21 Order 代码
package com.ieening.acyclicdependency.original.order;

import java.math.BigDecimal;

import com.ieening.acyclicdependency.original.account.Account;

public class Order {

    private BigDecimal chargeAmount;
    private Account account;

    public void setAccount(Account account) {
        this.account = account;
    }

    public Order(Account account, BigDecimal chargeAmount) {
        this.account = account;
        this.chargeAmount = chargeAmount;
    }

    public BigDecimal getChargeAmount() {
        return this.chargeAmount;
    }

    public BigDecimal pay() {
        BigDecimal discount = new BigDecimal(1).subtract(this.account.getDiscountAmount());
        BigDecimal paidAmount = this.chargeAmount.multiply(discount);

        return paidAmount;
    }
}
代码清单1-22 Account 代码
package com.ieening.acyclicdependency.original.account;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import com.ieening.acyclicdependency.original.order.Order;

public class Account {
    private List<Order> orders;

    public BigDecimal getDiscountAmount() {
        // 根据账号下的订单数来模拟折扣力度
        if (orders.size() > 5) {
            return new BigDecimal(0.1);
        } else {
            return new BigDecimal(0.03);
        }
    }

    public List<Order> getOrders() {
        return this.orders;
    }

    public void createOrder(BigDecimal chargeAmount) {
        Order order = new Order(this, chargeAmount);
        if (orders == null) {
            orders = new ArrayList<Order>();
        }
        orders.add(order);
    }

    public BigDecimal pay() {
        BigDecimal total = new BigDecimal(0);
        for (Order order : orders) {
            total = total.add(order.pay());
        }
        return total;
    }
}


1.1 提取中介者

提取中介者的核心思想是把两个相互依赖的组件中的交互部分抽象出来形成一个新的组件,而新组件同时包含着对原有两个组件的引用,这样就把循环依赖关系剥离出来并提取到一个专门的中介者组件中,关联关系如下图所示。中介者组件的实现非常简单,通过提供一个支付方法(pay)来对循环依赖进行了剥离,该方法同时依赖于AccountOrder对象,并实现了原有Order中根据订单数量支付的业务逻辑。中介者PaymentMediator类的实现代码如代码清单1-23所示。

循环依赖提取中介者

代码清单1-23 PaymentMediator 代码
package com.ieening.acyclicdependency.escalate.mediator;

import java.math.BigDecimal;
import java.util.List;

import com.ieening.acyclicdependency.escalate.account.Account;
import com.ieening.acyclicdependency.escalate.order.Order;

public class PaymentMediator {
    private Account account;

    public PaymentMediator(Account account) {
        this.account = account;
    }

    public BigDecimal pay(Order order) {
        BigDecimal discount = new BigDecimal(1).subtract(this.account.getDiscountAmount());
        return order.getChargeAmount().multiply(discount);
    }

    public BigDecimal pay(List<Order> orders) {
        BigDecimal total = new BigDecimal(0);
        for (Order order : orders) {
            total = total.add(pay(order));
        }
        return total;
    }
}

1.2 转移业务逻辑

转移业务逻辑方法的实现思路在于提取一个专门的业务组件来完成对折扣的计算。这样,Order原本对Account的依赖就转移到了对这个业务组件的依赖,而这个业务组件本身不需要依赖任何对象。实现转移业务逻辑后的关联关系如下图所示:

代码清单1-24 DiscountCalculator 代码
package com.ieening.acyclicdependency.demote.calculator;

import java.math.BigDecimal;

public class DiscountCalculator {
    private Integer orderNums;

    public DiscountCalculator(Integer orderNums) {
        this.orderNums = orderNums;
    }

    public BigDecimal getDiscountAmount() {
        if (orderNums.intValue() > 5) {
            return new BigDecimal(0.1);
        } else {
            return new BigDecimal(0.03);
        }
    }
}

1.3 引入回调

引入回调的本质上是一种双向调用模式,也就是说,被调用方在被调用的同时也会调用对方。在实现上,我们可以提取一个用于计算折扣的业务接口,然后让Account去实现这个接口。我们同样将这个接口命名为DiscountCalculator,其中包含一个计算折扣的方法定义。这样,Order在计算价格时只需要依赖这个业务接口,而不需要关心这个接口的具体实现类,如下图所示。

代码清单1-25 DiscountCalculator 代码
package com.ieening.acyclicdependency.callback.calculator;

import java.math.BigDecimal;

public interface DiscountCalculator {
    public BigDecimal getDiscountAmount();
}
代码清单1-25 Account 代码
package com.ieening.acyclicdependency.callback.account;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import com.ieening.acyclicdependency.callback.calculator.DiscountCalculator;
import com.ieening.acyclicdependency.callback.order.Order;

public class Account implements DiscountCalculator {
    private List<Order> orders;

    public BigDecimal getDiscountAmount() {
        if (orders.size() > 5) {
            return new BigDecimal(0.1);
        } else {
            return new BigDecimal(0.03);
        }
    }

    public List<Order> getOrders() {
        return this.orders;
    }

    public void createOrder(BigDecimal chargeAmount) {
        Order order = new Order(this, chargeAmount);
        if (orders == null) {
            orders = new ArrayList<Order>();
        }
        orders.add(order);
    }

    public BigDecimal pay() {
        BigDecimal total = new BigDecimal(0);
        for (Order order : orders) {
            total = total.add(order.pay());
        }
        return total;
    }
}
代码清单1-25 Order 代码
package com.ieening.acyclicdependency.callback.order;

import java.math.BigDecimal;

import com.ieening.acyclicdependency.callback.calculator.DiscountCalculator;

public class Order {

    private BigDecimal chargeAmount;
    private DiscountCalculator discounter;

    public Order(DiscountCalculator discounter, BigDecimal chargeAmount) {
        this.discounter = discounter;
        this.chargeAmount = chargeAmount;
    }

    public BigDecimal getChargeAmount() {
        return this.chargeAmount;
    }

    public BigDecimal pay() {
        BigDecimal discount = new BigDecimal(1).subtract(this.discounter.getDiscountAmount());
        BigDecimal paidAmount = this.chargeAmount.multiply(discount);

        return paidAmount;
    }
}

完整的代码请查看:learnSpring – acyclicdependency

  • 21
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值