如何避免类之间的循环依赖

      最近在看《Java应用架构设计 模块化模式与OSGi》,深有感触,在此做些总结。(电子版可以在Java1234.com上下载到)

      在使用Java开发中,各种依赖不可避免。比如类之间的继承,jar包之间的相互依赖。依赖在某种程度上不可避免,但是过多的依赖势必会增加系统的复杂性,使代码难以阅读,从而成为团队开发的阻碍。循环依赖尤其糟糕。

     循环依赖存在与多种实体之间,尤其是类、包、模块之间。当两个类相互引用时,就会出现循环依赖。下面摘抄书中的一个例子。

     如图1.1所示,有Customer和Bill两个类。在本例中,Customer有一个Bill的实例列表,而Bill实例也引用Customer来计算折扣总额。这也成为双向关联(bidirectional association)。对于维护和测试,这将是一个将是一个问题,因为在不引用另一个类的情况下,你不能单独的对其中一个类做任何事情。

  image

图1.1 类之间的循环依赖

      代码清单1.1展示了Customer类,代码清单1.2展示了Bill类。(为了简化,每个类的特定部分进行了省略。)在这里清楚展示了循环依赖。  

package com.scott.cust;

import java.util.*;
import java.math.BigDecimal;
import com.scott.bill.*;

public class Customer {
   private List<Bill> bills;
   //特定Customer的折扣根据订单数目计算
   public BigDecimal getDiscountAmount() {
       if (bills.size() > 5) {
           return new BigDecimal(0.1);
       } else {
           return new BigDecimal(0.03);
       }
   }
   
   public void createBill() {
       Bill bill = new Bill(this);
       if (bills == null) {
           bills = new ArrayList<Bill>();
       }
       bills.add(bill);
   }

}
代码清单1.1 Customer
package com.scott.bill;

import com.scott.cust.*;
import java.math.BigDecimal;

public class Bill {
   private Customer customer;
   
   public Bill(Customer customer) {
        this.customer = customer;   
   }
   
   public BigDecimal pay() {
       BigDecimal discount =  new BigDecimal(1),subtract(
            this.customer.getDiscountAmount()).setScale(2,
            BigDecimal.ROUND_HALF_UP);
       //确认折扣和应付款代码省略
       return paidAmount;

  }

}
代码清单1.2 Bill

      可以有多种方式打破循环依赖(笔者目前所知就是引入抽象),其中之一就是引入抽象,如图1.2所示。现在,借助mock的DiscountCaculator,Bill就可以容易的进行(单元)测试了。当然,测试Customer依旧需要Bill的参与。单着不是循环的问题了,这里暂时不做讨论。很显然,引入DiscountCalculator打破了Customer和Bill类之间依赖。但是,它能打破所有的循环依赖吗,包括可能存在与模块之间的?

image

图1.2 打破循环   

代码清单1.3展示了修改后的Customer类,它实现了DiscountCalculator接口,改接口如程序清单4.4所示。

package com.scott.cust;

import java.util.*;
import java.math.BigDecimal;
import com.scott.bill.*;

public class Customer implements DiscountCalculator {
   private List<Bill> bills;
   //特定Customer的折扣根据订单数目计算
   public BigDecimal getDiscountAmount() {
       if (bills.size() > 5) {
           return new BigDecimal(0.1);
       } else {
           return new BigDecimal(0.03);
       }
   }
   
   public List<Bill> getBills() {
       return this.bills;
   }

   public void createBill() {
       Bill bill = new Bill(this);
       if (bills == null) {
           bills = new ArrayList<Bill>();
       }
       bills.add(bill);
   }

}
代码清单1.3 修改后的Customer
package com.scott.bill;

import java.math.BigDecimal;

public interface DiscountCalculator {
    public BigDecimal getDisCountAmount();
}
代码清单1.4 DiscountCalculator

 

转载于:https://www.cnblogs.com/scottwang/p/4222323.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值