응집도와 결합도에 대한 내용을 공부하다보니,자바에서 말하는 모듈이란 개념과 프로그램의 독립적인 기능의 단위인 모듈의 개념이 좀 헷갈렸다.
그래서 그 부분과 응집도, 결합도를 함께 정리할까한다.
일반적으로 우리가 모듈의 응집도는 높이고, 모듈간의 결합도는 낮추어야한다는 이야기를 할 때의 모듈은 소프트웨어 공학에서의 모듈
을 의미한다.
이 때 모듈은 단순하게 하나의 프로그램을 이루는 단위의 코드들로 생각하면 된다. 즉 어떤 단위로 할지에 대한 클래스로 할지, 메서드로할지 패키지로 할지는 개발자가 정하는 것이다.
public int add(int a,int b){
return a+b;
}
더하기 기능 자체를 모듈화하였다.
이 때는 다른 모듈을 이 내부에서 사용하지 않기 때문에, 매우 낮고, 더하기 기능 하나만 수행하기 때문에 응집도는 매우 높다.
public class UserService {
public User getUserById(Long id) { ... }
public void updateUser(User user) { ... }
}
사용자 관련 기능을 모듈화하였다.
이때는 사용자 관리 기능만이 들어있기에, 응집도는 높지만, 다른 클래스를 사용하는 경우가 많이 생길 것이므로, 결합도는 높아질 여지가 있다.
com.example.utils // 유틸리티 기능 모듈
├── MathUtils.java
├── StringUtils.java
유틸리티 기능을 패키지로 모듈화했다.
이 때의 응집도는 그렇게 높다고 보여지지않는다.왜냐하면, 문자열 관련 기능, 수학관련 기능등이 함께 들어있기 때문이다.
util패키지는 필연적으로 다른 패키지에서 많이 사용할 것이므로, 결합도 또한 높아질 수 있다.
자바에서 public
키워드를 이용해서 클래스를 만들면 모든 패키지 내에서 접근을 할 수 있기 때문에, 정보 은닉의 측면에서 그다지 좋지 않다.
package com.example.utils;
public class MathUtils { // ✅ public → 모든 패키지에서 접근 가능
public static int add(int a, int b) {
return a + b;
}
}
package com.example.app;
import com.example.utils.MathUtils; // ✅ 다른 패키지에서도 접근 가능
public class Main {
public static void main(String[] args) {
int result = MathUtils.add(5, 10);
System.out.println(result);
}
}
이 때 자바 모듈의 기능은 여러 패키지들을 그룹화시켜서, 이 내부에서만 클래스를 사용할 수 있게 만드는 것이다. 이를 통해서 정보 은닉을 지킬 수 있음.
myapp/ // 모듈
├── module-info.java // 모듈 선언 파일
├── com.example.utils // 유틸리티 기능 제공 (외부 공개)
│ ├── MathUtils.java
├── com.example.internal // 내부 전용 패키지 (외부 비공개)
│ ├── InternalHelper.java
그런데 이중에서 Math.utils를 다른 모듈의 패키지에서 사용하고 싶다면 아래처럼 구현을 통해서 가능하다
module myapp {
exports com.example.utils; // ✅ 이 패키지는 외부에 공개
// com.example.internal 패키지는 공개하지 않음 (모듈 내부에서만 사용 가능)
}
이를 통해서 자바의 캡슐화를 더 잘 구현할 수 있다.
위에서 예시로 들었지만, 응집도는 모듈 내부요소들이 얼마나 연관되어있는지, 즉 내부 요소들이 얼마나 같은 기능을 수행하는지를 나타낸다.
하나의 모듈내에서 너무 많은 기능을 수행해서 응집도가 낮아진다면, 기능 추가나, 변경시에 기존의 변경해야하는 코드와 변경하면 안되는 코드가 모듈내에서 공존해서, 유지 보수성이 낮아진다.
이 때문에 모듈의 응집도는 높으면 높을 수록 좋다.
응집도가 모듈 내부관점에서 보는 것이라면, 결합도는 모듈 외부 관점에서 모듈들 사이의 의존성을 나타낸다.
모듈 사이의 결합도가 높다면, 기능이 추가,변경됨에 따라서 여러 모듈들을 변경해야하므로, 유지보수성이 안 좋다.
따라서 결합도는 낮은게 좋다
즉 응집도는 높을 수록 결합도는 낮을 수록 좋다.
public class Calculation{
public int a=0;
public int b=0;
}
public class ReuturnResult{
public Calculation aClass=new Calculation();
public int plusA(){
aClass.a+=1;
return a.
}
}
Calculate 클래스의 경우 멤버 변수가 public으로 열려있어서, 위처럼 결과를 반환해야하는 클래스에서, 연산까지 수행을 한다.
즉 응집도가 매우 떨어지는 결과를 초래한다.
또한 public을 사용해서 Calculation를 정의하는 경우, aClass가 다른 클래스에서도 사용할 수 있으므로, 결합도가 올라간다.
위의 경우는 객체 생성까지 해주었으므로, 더욱 결합도가 올라갈 것이다.
또한 Calculation의 변수인 a까지 ReuturnResult클래스에서 사용되므로, 결합도가 올라간다.
public class Calculation{
private int a=0;
private int b=0;
public int plusA(){
this.a+=1;
}
}
public class ReuturnResult{
private Calculation aClass
public ReuturnResult(Calculation c){
aClass=c;
}
public int returnA(){
aClass.plus();
return aClass.a;
}
}
이렇게 캡슐화를 지키면 위에서 말한 결합도,응집도 문제를 해결 가능하다.