💡 객체지향 & 소프트웨어에서 중요한 응집도와 결합도에 대하여 학습하였습니다.
소프트웨어 모듈 독립성
- 소프트웨어에서 크고 복잡한 문제가 발생했을 때, 문제를 작은 부분으로 쪼개어서 하나씩 풀어나가야 합니다.
- 이런 경우 큰 문제를 작은 부분으로 쪼개어 해결하는 것을 모듈화라고 하며, 소프트웨어를 각 기능별로 나누어진 소스 단위를 뜻합니다.
- 독립적으로 컴파일 가능한 프로그램 혹은 하나의 함수나 클래스도 모듈이 될 수 있습니다.
- 좋은 소프트웨어 일수록 모듈의 독립성이 높다라고 표현할 수 있습니다.
- 좋은 모듈화는 목적에 맞는 기능만으로 모듈을 나누게 됩니다.
- 각각의 모듈은 주어진 기능만을 독립적으로 수행하기 때문에 재사용성이 높고 코드의 이해와 수정이 용이합니다.
- 해당 모듈을 수정하더라도 다른 모듈에 끼치는 영항이 적으며, 오류가 발생하더라도 기능 단위로 잘 나누어 져 있기 때문에 손쉽게 문제를 발견해 해결할 수 있기도 합니다.
- 이러한 모듈의 독립성은 모듈의 결합도 와 응집도 의 기준 단계로 측정됩니다.
결합도(Coupling)
- 결합도는 모듈간의 상호 의존 정도 또는 연관된 관계의 끈끈한 정도를 의미합니다.
- 결합도가 높은 클래스는 다른 클래스와 연관 관계가 높으며, 하나의 클래스 구조를 변경하면 그와 연관된 클래스를 변경해야 하는 위험이 있습니다.
- 도메인이나 객체 사용 코드를 변경해야 함으로, 유지보수 측면에서 좋지 않습니다.
class DatabaseHelper {
fun connect() {
println("Connected to the database.")
}
fun disconnect() {
println("Disconnected from the database.")
}
fun executeQuery(query: String): String {
println("Executing query: $query")
return "Results"
}
}
class UserManager {
private val dbHelper = DatabaseHelper()
fun addUser(name: String) {
dbHelper.connect()
dbHelper.executeQuery("INSERT INTO users (name) VALUES ('$name')")
dbHelper.disconnect()
}
fun removeUser(name: String) {
dbHelper.connect()
dbHelper.executeQuery("DELETE FROM users WHERE name = '$name'")
dbHelper.disconnect()
}
fun getUser(name: String): String {
dbHelper.connect()
val result = dbHelper.executeQuery("SELECT * FROM users WHERE name = '$name'")
dbHelper.disconnect()
return result
}
}
- 위는 결합도가 높은 클래스의 예시입니다.
- UserManager 클래스는 DatabaseHelper 클래스를 직접 인스턴스화 하고 있으며, 이는 DatabaseHelper 클래스의 변경이 UserManager의 직접적인 영향을 미친다는 것을 의미합니다.
- 현실세계의 예로 든다면, 핸드폰의 부품을 변경해야 할 때, 핸드폰 기기를 새로 구매한다는 예로 들 수 있습니다.
- 객체지향의 관점에서 결합도는 클래스 또는 메서드가 협력에 필요한 적절한 수준의 관계만을 유지해야 합니다.
- 클래스들 간에 연관이 있을때 인터페이스로 제대로 분리되어 있지 않고 불필요하게 많은 정보를 알고 있다면, 이는 결합도가 높게 측정되게 됩니다.
- 따라서 좋은 소프트웨어는 낮은 결합도를 가지고 있다라고 말할 수 있습니다.
응집도(Cohesion)
- 응집도는 하나의 클래스가 기능에 집중하기 위한 모든 정보와 역할을 가지고 있어야 한다는 의미입니다.
- 한 모듈 내의 구성 요소 간의 밀접한 정도를 의미하며, 한 모듈이 하나의 기능에 대한 책임을 가지고 있는 것은 응집도가 높은 것입니다.
- 만약 한 모듈이 여러 기능을 갖고 있다면, 응집도가 낮다고 할 수 있습니다.
- 응집도가 높은 모듈은 하나의 모듈 안에 함수나 데이터와 같은 구성 요소들이 하나의 기능을 구현하기 위해 필요한 것들만 배치되어 있으며, 긴밀하게 협력합니다.
- 반면에 응집도가 낮은 모듈은 모듈 내부에 서로 관련 없는 함수나 데이터들이 존재하거나, 관련성이 적은 여러 기능들이 서로 다른 목적을 추구하며 산재해 있습니다.
- 응집도가 낮은 예
- UserService 클래스는 사용자 관리, 이메일 전송, 리포트 생성 등 여러 책임을 수행하고 있습니다.
- 이 클래스의 메서드들은 서로 밀접하게 관련되지 않은 작업들을 처리합니다.
- 이는 클래스의 응집도를 낮추고 유지 보수성을 떨어뜨립니다.
class UserService {
fun addUser(user: User) {
// Logic to add user to the database
}
fun removeUser(userId: String) {
// Logic to remove user from the database
}
fun getUser(userId: String): User? {
// Logic to retrieve user from the database
}
fun sendWelcomeEmail(user: User) {
// Logic to send welcome email to the user
}
fun generateUserReport(userId: String): Report {
// Logic to generate a report for the user
}
}
- 응집도가 높은 예
- 각 클래스들이 단일 책임에 집중하고 있습니다.
- 이로써 각 클래스의 응집도가 높아지고, 유지 보수성과 재사용성이 향상되었습니다.
class UserRepository {
fun addUser(user: User) {
// Logic to add user to the database
}
fun removeUser(userId: String) {
// Logic to remove user from the database
}
fun getUser(userId: String): User? {
// Logic to retrieve user from the database
}
}
class EmailService {
fun sendWelcomeEmail(user: User) {
// Logic to send welcome email to the user
}
}
class UserReportService {
fun generateUserReport(userId: String): Report {
// Logic to generate a report for the user
}
}
- 이처럼 클래스를 분리함으로써 각 클래스가 하나의 책임에 집중하도록 한다면, 코드의 응집도가 높아지고 아래와 같은 장점을 얻을 수 있습니다.
- 코드의 가독성 향상
- 유지 보수성 향상
- 테스트 용이성 향상
- 응집도가 높은 클래스는 단일 책임을 가진 클래스, 다른 클래스와 잘 협력하는 클래스라고 할 수 있습니다.
참고
https://inpa.tistory.com/entry/OOP-💠-객체의-결합도-응집도-의미와-단계-이해하기-쉽게-정리