CRITICAL
Rule Definition
When two packages refer to each other through a call, the result is a circular dependency. Neither packages can function without the other, and so neither is reusable without the other. In some cases redesign may eliminate these dependencies.
When circular references are necessary, redesign it to ensure reusability. The same problem happen when some classes from a package A inherit from classes of a package B and other classes from package B inherit from other classes from package A. This rule can be extended to circular dependencies for more than 2 packages (for example a package A call a package B that call a package C, that call package A).
Remediation
If there are circular relationships among packages, the partitioning is not clear and should be redesigned. Use CAST Enlighten to see all dependencies to fix.
Violation Code Sample
package account; import user.User; public class AccountHolder { private User user; public void setUser(User newUser) {user = newUser;} synchronized void depositFunds(String username, double amount) { // Use a utility method of User to check whether username exists if (user.exists(username)) { // Deposit the amount } } protected double getBalance(String accountNumber) { // Return the account balance return 1.0; } } package user; import account.AccountHolder; public class UserDetails extends AccountHolder { public synchronized double getUserBalance(String accountNumber) { // Use a method of AccountHolder to get the account balance return getBalance(accountNumber); } } public class User { private AccountHolder acc; public boolean exists(String username) { if(username != "") { acc = new AccountHolder(); } // Check whether user exists return true; // Exists } }
Fixed Code Sample
package bank; public interface BankApplication { void depositFunds(BankApplication ba, String username, double amount); double getBalance(String accountNumber); double getUserBalance(String accountNumber); boolean exists(String username); } package account; import bank.BankApplication; // Import from a third package class AccountHolder { private BankApplication ba; public void setBankApplication(BankApplication newBA) { ba = newBA; } public synchronized void depositFunds(BankApplication ba, String username, double amount) { // Use a utility method of UserDetails // to check whether username exists if (ba.exists(username)) { // Deposit the amount } } public double getBalance(String accountNumber) { // Return the account balance return 1.0; } } package user; import account.AccountHolder; // One-way dependency import bank.BankApplication; // Import from a third package public class UserDetails extends AccountHolder implements BankApplication { public synchronized double getUserBalance( String accountNumber) { // Use a method of AccountHolder to get the account balance return getBalance(accountNumber); } public boolean exists(String username) { // Check whether user exists return true; } }
Reference
http://en.wikipedia.org/wiki/Circular_dependency
Related Technologies
JEE
Technical Criterion
Architecture - Multi-Layers and Data Access
About CAST Appmarq
CAST Appmarq is by far the biggest repository of data about real IT systems. It's built on thousands of analyzed applications, made of 35 different technologies, by over 300 business organizations across major verticals. It provides IT Leaders with factual key analytics to let them know if their applications are on track.