C言語におけるモジュール結合度を弱いものから強いものまで、コード例を交えて説明します。
1. データ結合(最も弱い結合)
データ結合は、モジュール間で単純なデータ(基本型)のみをパラメータとして渡す方法です。
// モジュールA
int calculate_area(int width, int height) {
return width * height;
}
// モジュールB
void main() {
int w = 5;
int h = 10;
int area = calculate_area(w, h);
printf("Area: %d\n", area);
}
この例では、単純な整数値のみを引数として渡しており、モジュール間の依存関係が最小限です。
2. スタンプ結合
スタンプ結合は、構造体などの複合データ型を介して通信する方式です。
// 共有構造体
typedef struct {
char name[50];
int age;
float salary;
} Employee;
// モジュールA
void print_employee_details(Employee emp) {
printf("Name: %s, Age: %d, Salary: %.2f\n", emp.name, emp.age, emp.salary);
}
// モジュールB
void main() {
Employee emp = {"John Doe", 30, 50000.0};
print_employee_details(emp);
}
この例では、Employee
構造体を通じてデータを共有していますが、モジュールAは構造体のフィールドにのみアクセスし、変更はしていません。
3. 制御結合
制御結合は、あるモジュールが他のモジュールの内部ロジックに影響を与える場合に発生します。
// モジュールA
void process_data(int data[], int size, int mode) {
if (mode == 0) {
// 合計を計算
int sum = 0;
for (int i = 0; i < size; i++) {
sum += data[i];
}
printf("Sum: %d\n", sum);
} else if (mode == 1) {
// 平均を計算
int sum = 0;
for (int i = 0; i < size; i++) {
sum += data[i];
}
printf("Average: %.2f\n", (float)sum / size);
}
}
// モジュールB
void main() {
int data[] = {1, 2, 3, 4, 5};
process_data(data, 5, 0); // 合計モード
process_data(data, 5, 1); // 平均モード
}
この例では、モジュールBがモードフラグを通じてモジュールAの動作を制御しています。これにより、モジュール間の結合度が高まります。
4. 外部結合
外部結合は、複数のモジュールが同じグローバルデータを参照・変更する場合に発生します。
// グローバル変数
int g_counter = 0;
// モジュールA
void increment_counter() {
g_counter++;
printf("Counter incremented to: %d\n", g_counter);
}
// モジュールB
void reset_counter() {
g_counter = 0;
printf("Counter reset to: %d\n", g_counter);
}
// モジュールC
void main() {
increment_counter();
increment_counter();
reset_counter();
increment_counter();
}
この例では、複数のモジュールがグローバル変数g_counterにアクセスして変更しています。
5. 共通結合
共通結合は、複数のモジュールが共有メモリ領域にアクセスする場合に発生します。
// 共有メモリ領域
typedef struct {
int status;
char message[100];
float values[10];
} SharedData;
SharedData shared_memory;
// モジュールA
void update_status(int new_status) {
shared_memory.status = new_status;
}
// モジュールB
void update_message(const char* new_message) {
strcpy(shared_memory.message, new_message);
}
// モジュールC
void update_values(float new_values[], int size) {
for (int i = 0; i < size && i < 10; i++) {
shared_memory.values[i] = new_values[i];
}
}
// モジュールD
void main() {
update_status(1);
update_message("Processing");
float vals[] = {1.1, 2.2, 3.3};
update_values(vals, 3);
}
6. 内容結合(最も強い結合)
内容結合は、あるモジュールが他のモジュールの内部実装に直接アクセスする場合に発生します。
// モジュールA
void process_array() {
static int internal_array[100];
static int count = 0;
// 内部配列に値を追加
internal_array[count++] = count;
printf("Added value: %d\n", count);
}
// モジュールB - 内部実装に不正にアクセス
extern int internal_array[];
extern int count;
void hack_module_a() {
// モジュールAの内部変数に直接アクセス
internal_array[count] = 9999;
count += 10;
printf("Hacked internal state!\n");
}
void main() {
process_array();
hack_module_a();
process_array();
}
この例では、モジュールBがモジュールAの内部実装詳細(静的変数)に直接アクセスしています。これは非常に強い結合であり、モジュールAの実装変更がモジュールBに即座に影響を与えるため、避けるべきです。
各種結合度は、上から下に向かうにつれて強くなり、コードの保守性や再利用性が低下します。良いプログラム設計では、できるだけ弱い結合(データ結合やスタンプ結合)を目指すべきです。