프로그래밍을 하면서 "~을 사용하게 되면 결합도가 낮아지고, 응집도가 높아지는 장점을 가질 수 있다." 라는 이야기를 많이 본 경험이 있습니다. (특히 cs 공부하다보면)
자주 보인다는것은 그만큼 중요하고 기초적인 이야기라는 뜻입니다.
결합도는 무엇이고, 응집도는 무엇인지 알아보도록 하겠습니다.
프로그래밍을 하다보면 특정 기능을 수행하는 부분을 모듈로 분리하여 사용해줍니다.
이렇게 독립적으로 분리를 해주면, 해당 기능이 필요한 부분에 모듈을 불러와 쉽게 기능을 적용시켜줄 수가 있습니다. 또한 이 기능에 어떤 부분이 변경이 되어야한다면, 이 모듈내부만 수정하면 이 모듈을 사용하고있는 곳에서 동일하게 적용이 될것입니다.
즉, 모듈을 사용함으로써, 재사용성이 높아지고 유지보수가 좋아집니다.
좋은 모듈이란, 용도와 목적에 맞는 기능을 가지고 있고 세분화되어 있을수록 좋은 모듈이라 할 수 있습니다.
즉, 좋은 모듈은 특정 기능만 제공하는 독립적인 모듈이어야 합니다.
독립적인 모듈이란, 자신의 기능만을 수행하고 외부 모듈에 많이 의존하지 않는 것입니다.
즉, 외부 요소에 영향을 받지않고 명확한 값을 반환하는 것입니다.
자신의 특정한 기능만을 수행하기 위해 관련되어있는 요소로 구성되어있는 정도를 응집도
,
요소가 기능을 수행하기 위해 모듈과 모듈간의 상호 결합 정도를 결합도
라고 합니다.
독립적인 모듈을 통해 재사용성이 좋고 유지보수가 쉽게 프로그래밍 하기 위해서는 결합도가 낮고 응집도가 높을 수록 좋은 프로그래밍
이 되게 됩니다.
결합도
란, 요소가 기능을 수행하기 위해 모듈과 모듈간의 상호 결합 정도를 나타냅니다.
낮은 결합도 장점
결합도는 6개로 구분할 수 있습니다.
결합도가 낮은 순으로 아래와 같이 구분할 수 있습니다.
자료 결합도 < 스탬프 결합도 < 제어 결합도 < 외부 결합도 < 공통 결합도 < 내용결합도
자료결합도는 결합도가 가장낮은 좋은 형태입니다. 각 모듈끼리 단순히 파라미터만을 가지고 데이터를 주고 받고 기능을 처리해주도록 구조화된 것입니다.
public int payback(int money){
return money*0.2;
}
모듈간의 인터페이스로 배열 또는 객체들이 전달되는 구조 입니다. 전달되는 객체의 타입이 변경되게되면 해당 모듈에서도 변경이 발생하게 됩니다.
public int buy(int money, Policy policy){
return policy.pay(money);
}
어떤 모듈이 다른 모듈의 내부의 논리적 흐름을 제어하는 요소를 전달하는 구조 입니다.
public int payback(int money, boolean isVIP){
if(isVIP){
return money * 0.3;
}
else{
return money 0.03;
}
}
외부에 있는 모듈의 데이터를 참조하는 구조 입니다.
여러 모듈이 하나의 데이터 영역을 참조하여 사용하는 구조입니다. 전역변수를 예로 들수 있습니다.
가장 높은 결합도를 가지는 형태입니다. 어떤 모듈이 사용하려는 다른 모듈의 데이터와 기능을 참조하는 구조입니다.
사용하고자 하는 다른 모듈의 내용을 알고 있어야합니다.
객체간의 의존관계에 대해서는 강한 의존관계 구조를 가지고 있을때 높은 결합도라고 합니다.
public class Car{
private final Tire tire;
public Car(){
this.tire = new Tire();
}
}
내부에서 의존 객체를 직접 생성해주게 되면 외부에서 의존관계에 대해 제어하지 못하기 때문에 두 객체간의 의존도가 높게 형성됩니다.
public class Car{
private final Tire tire;
public Car(Tire tire){
this.tire = tire;
}
}
위의 코드와 같이 외부에서 해당 객체의 의존객체를 주입해줌으로써 의존 객체에 대해 유연하게 대처하고 재활용성이 높아질 수 있습니다.
응집도
란, 특정 기능을 수행하기 위해 관련되어있는 요소로 구성되어 있는 정도입니다.
높은 응집도 장점
응집도는 7개로 구분할 수 있습니다.
응집도가 높은순으로 아래와 같습니다.
기능적 응집도 > 순차적 응집도 > 교환적 응집도 > 절차적 응집도 > 일시적 응집도 > 논리적 응집도 > 우연적 응집도
가장 높은 응집도를 나타내는 구조입니다. 내부 요소들이 하나의 기능을 수행하기 위해 구성된 구조입니다.
한 요소의 출력값이 다른 요소의 기능적 입력값으로 사용되도록 구성된 구조입니다.
각 요소들이 순차적으로 호출됩니다.
public void write(Path readPath, Path writePath){
String content = readFile(readPath);
writePath(writePath, content);
}
모든 요소들이 동일한 입력값 또는 출력값을 받아 다른 기능을 수행하는 경우입니다.
순차적 응집도와 다르게 각 요소들의 실행 순서가 중요하지 않습니다.
public String minPayback(int money){
int vipPayback = getVipPayback(money);
int firstPayback = getFirstUserPayback(money);
int otherPayback = getOtherPayback(money);
return Math.min(vipPayback, Math.min(firstPayback, otherPayback));
}
기능 요소들이 순차적으로 실행되지만 기능 요소가 아닌 흐름 제어 요소로 전달되는 경우입니다.
public String read(Path path){
String content = "";
boolean isFileReadable = checkReadable(path);
if(isFileReadable){
content = readFile(path);
}
...
return content;
}
각 기능들이 순차적이 아니라 특정 시점에 반드시 실행되는 경우입니다.
프로그램이 실행될때 로그를 발생시키거나, 예외 발생시 기능을 수행하는 경우입니다.
유사하거나 특정 형태로 분류되는 처리 요소들이 한 모듈에서 처리되는 경우입니다.
응집도가 가장 낮은 구조입니다. 각 구성요소들이 아무런 관계가 없는 경우입니다.
요약하자면, 응집도가 높을수록(하나의 책임만 가질수록)
유지보수가 쉽고 결합도가 낮을수록(다른 모듈에 의존도가 낮을수록)
다른 모듈의 변경에 유연하게 대처할 수 있게 되어 좋은 프로그래밍을 할 수 있게 됩니다.
https://madplay.github.io/post/coupling-and-cohesion-in-software-engineering