응집도
응집도는 클래스 또는 모듈 내부의 구성 요소들이 얼마나 밀접하게 관련되어 있는지를 나타냅니다.
따라서 응집도가 높을수록 좋은 설계라고 평가됩니다.
응집도가 낮은 경우
응집도가 낮은 경우란, 서로 관련 없는 기능들이 하나의 클래스에 포함된 경우를 말합니다.
이를 하나의 목적을 가진 팀과 각기 다른 목적을 가진 팀에 비유할 수 있습니다.
응집도가 높은 경우
응집도가 높은 경우는 서로 관련 있는 모듈들만 하나의 class에 있는 경우입니다.
응집도 실제 예시
아래 기능을 제공하는 코드를 구현해 봅시다
- 특정 문자열을 받고 메시지를 출력
- 두 수의 합을 반환
- 특정 문자열을 받고 역으로 출력
그리고 추가적으로 아래 기능이 추가되는 상황입니다
- 두 수의 곱을 반환하는 기능 추가
- 특정 문자열을 받고 메시지를 출력하기 전 대문자로 변환합니다.
응집도가 낮은 코드
Utility 클래스 하나에 모든 걸 구현해 보겠습니다.
class를 사용하긴 하는데 class 하나에 모든 걸 다 집어넣는 구조로 설계하는 경우가 있습니다.
- 목적이 다른 기능이 섞여 있습니다.
- 하나의 class에 모든 기능이 집중되어 유지 보수가 어렵습니다.
위와 같은 이유로 좋은 설계라고 보기 어렵습니다.
//기능을 추가 전 예시코드
#include <iostream>
#include <string>
using namespace std;
class Utility {
public:
void printMessage(const string& message) {
cout << "Message: " << message << endl;
}
void calculateSum(int a, int b) {
cout << "Sum: " << (a + b) << endl;
}
void reverseString(const string& str) {
string reversed = string(str.rbegin(), str.rend());
cout << "Reversed: " << reversed << endl;
}
};
int main() {
Utility util;
util.printMessage("Hello");
util.calculateSum(5, 10);
util.reverseString("world");
return 0;
}
//기능을 추가 후 예시코드
#include <iostream>
#include <string>
#include <algorithm> // for transform
using namespace std;
class Utility {
public:
void printMessage(const string& message) {
string upperMessage = message;
transform(upperMessage.begin(), upperMessage.end(), upperMessage.begin(), ::toupper);
cout << "Message: " << upperMessage << endl;
}
void calculateSum(int a, int b) {
cout << "Sum: " << (a + b) << endl;
}
void calculateProduct(int a, int b) {
cout << "Product: " << (a * b) << endl;
}
void reverseString(const string& str) {
string reversed = string(str.rbegin(), str.rend());
cout << "Reversed: " << reversed << endl;
}
};
int main() {
Utility util;
util.printMessage("Hello");
util.calculateSum(5, 10);
util.calculateProduct(5, 10);
util.reverseString("world");
return 0;
}
위 두 코드를 보시면, 특정 기능이 필요 할 때마다 클래스를 수정을 해야합니다.
또한 한 눈에 봐도 하나의 클래스가 너무 많은 기능을 가지고 있고, 그 기능의 역할이 일치 하지 않으니 코드리딩 속도도 현저하게 떨어집니다.
응집도가 높은 코드
응집도를 높이기 위해 클래스를 목적에 따라 나누어 구현할 수 있습니다.
- 기능 변경이 필요할 때 특정 class만 수정하면 됩니다.
- 관련된 class끼리 정보를 공유하여 코드의 구조가 명확해집니다.
//기능 추가 전 예시코드
#include <iostream>
#include <string>
#include <algorithm> // for transform
using namespace std;
class MessageHandler {
public:
void printMessage(const string& message) {
cout << "Message: " << message << endl;
}
};
class Calculator {
public:
void calculateSum(int a, int b) {
cout << "Sum: " << (a + b) << endl;
}
};
class StringManipulator {
public:
void reverseString(const string& str) {
string reversed = string(str.rbegin(), str.rend());
cout << "Reversed: " << reversed << endl;
}
};
int main() {
MessageHandler messageHandler;
messageHandler.printMessage("Hello");
Calculator calculator;
calculator.calculateSum(5, 10);
StringManipulator stringManipulator;
stringManipulator.reverseString("world");
return 0;
}
#include <iostream>
//기능 추가 후 예시코드
#include <string>
#include <algorithm> // for transform
using namespace std;
class MessageHandler {
public:
void printMessage(const string& message) {
string upperMessage = message;
transform(upperMessage.begin(), upperMessage.end(), upperMessage.begin(), ::toupper);
cout << "Message: " << upperMessage << endl;
}
};
class Calculator {
public:
void calculateSum(int a, int b) {
cout << "Sum: " << (a + b) << endl;
}
void calculateProduct(int a, int b) {
cout << "Product: " << (a * b) << endl;
}
};
class StringManipulator {
public:
void reverseString(const string& str) {
string reversed = string(str.rbegin(), str.rend());
cout << "Reversed: " << reversed << endl;
}
};
int main() {
MessageHandler messageHandler;
messageHandler.printMessage("Hello");
Calculator calculator;
calculator.calculateSum(5, 10);
calculator.calculateProduct(5, 10);
StringManipulator stringManipulator;
stringManipulator.reverseString("world");
return 0;
}
클래스 별로 관리를 하면 기능이 추가 될 때, 해당 클래스 수정하면 되기 때문에 응집도가 높다고 할 수 있습니다.