Coupling

결합력

Low Couping System(결합력이 낮아진다면)

Objective: Minimize coupling

How to achieve low couppling(결합력을 낮추는 방법)

Scale of Coupling

Pasted image 20241118180815.png

Message Coupling

내부x, 인터페이스 정의로만 이어져있음

Pasted image 20241130015658.png

Data Coupling

int GetTotalArea()
{
	int totalArea = 0 ;
	for ( i = 0 ; i < count ; i ++ ) {
	totalArea += GetArea(shapes[i].width, shapes[i].height);//Data Coupling
}
return totalArea ;
}

Pasted image 20241130020057.png

Warnings on Data Coupling

넓은 인터페이스를 피해라

int ReadCustomerInfo(char* ID, char* name, char* address, char* phone, char* SSN) 
{
}
int StoreCustomerInfo(char* ID, char* name, char* address, char* phone, char* SSN) {
}

해결: 구조체 사용

typedef struct _customerInfo {
char *name, *address, *phone, *SSN ;
} CUSTOMER_INFO ;

int ReadCustomerInfo(char* ID, CUSTOMER_INFO* info) {
}

int StoreCustomerInfo(char* ID, CUSTOMER_INFO info) {
}

TRAMP 데이터를 피해라

TRAMP 데이터

해결: 모듈 구조 재구조화

Stamp Coupling

typedef struct _customerInfo {
char *name, *address, *phone, *SSN ;
} CUSTOMER_INFO ;

int ReadCustomerInfo(char* ID, CUSTOMER_INFO* info) {
}

int StoreCustomerInfo(char* ID, CUSTOMER_INFO info) {
}

Warnings on Stamp Coupling

문제1: 필요없는 정보 같이 전달 => 아마 TRAMP 데이터?

typedef struct _customerInfo {
char *name, *address, *phone, *SSN ;
} CUSTOMER_INFO ;

int ValidatePhoneNumber(CUSTOMER_INFO* info)//고객 정보 전달
{
	/* 고객의 휴대폰 정보만 사용 */
}

해결1: 실제 사용되는 값만 전달

문제2: 번들링

int CalcTototalPurchaseCost(int pricePerItem, int dicountType, int itemCount, int tax)// 개당 가격, 할인타입, 개수, 세금 
{
}
typedef struct _stuff {
int pricePerItem, dicountType, itemCount, tax ;
} STUFF ;

int CalcTototalPurchaseCost(STUFF stuff) {
}

해결2-1: 연관없는 데이터를 모으지 마라

해결2-2: 간단한 데이터와 구조체 타입의 인터페이스 사용

Control Coupling

Forward Control

int GeneralIORoutine(int flag, void* buffer, int size) {
	if ( flag == 0 )
		/* READ data and store them into buffer */
	else
		/* WRITE data in buffer */
}

해결: 불리는 모듈(Callee)을 분리

int Read(void* buffer, int size) {
	/* read data and store them into buffer */
}
int Write(void* buffer, int size) {
	/* write data in buffer */
}

Backward Control(=inversion of authority)

해결: 서술적인 플래그 사용

유형 이름의 유형 예시
Control flag
(사용 => 상했다)
동사 다음 레코드를 읽는다 (Read next record)
이 고객을 거절한다 (Reject this customer)
마스터 파일을 되감는다 (Rewind master file)
Descriptive flag 형용사 달걀이 썩었다 (Egg is rotten)
우편번호가 숫자이다 (Zip code is numeric)
거래 파일이 끝에 있다 (Transaction file is at end)

Pasted image 20241130222821.png

External Coupling

Common Coupling

안좋은 이유

해결: 전역변수를 의미있는 파라미터로 변환

Pasted image 20241130230546.png
Pasted image 20241130230600.png

해결: 전역 변수 선언을 제한하고 지역 변수(scoped variables) 사용

int gA, gB, gC, gD, gE ;
void f1( ) {
/* access gA, gB, gC */
}
void f2( ) {
/* access gA, gB, gC */
}
void f3( ) {
/* access gD, gE */
}
void f4( ) {
/* access gD, gE */
}

위 코드를 아래와 같이

static int gA, gB, gC ;
void f1( ) {
	/* access gA, gB, gC */
}
void f2( ) {
	/* access gA, gB, gC */
}
static int gD, gE ;
void f3( ) {
	/* access gD, gE */
}
void f4( ) {
	/* access gD, gE */
}

해결: 전역 변수에 대한 접근 함수 정의

/* A.c */
static int gA;

void setA(int a) {
	gA = a ;
}
int getA( ) {
	return a ;
}
/* B.c */
static int gB;

void setB(int b) {
	gB = b ;
}
int getB( ) {
	return b ;
}
void f1( ) {
int x = getA( ) ;
	setA(x++) ;
}

void f2( ) {
int y = getB( ) ;
	setB(y+getA( )) ;
}

void f3( ) {
int z = getD( ) ;
	setE(z+getE( )) ;
}

void f4( ) {
	int u = getD( ) + getE( ) ;
	setE(u) ;
}

Content Coupling

  1. 모듈이 다른 모듈 내부를 참조하거나 변경할 때:

    • 한 모듈이 다른 모듈의 데이터를 직접 접근하거나 변경하는 경우.
    • 예: 한 모듈이 다른 모듈 내부의 변수나 상태를 직접 수정함.
  2. 모듈 간의 흐름 제어:

    • 한 모듈이 다른 모듈의 분기(branch)나 흐름(fall-through)에 영향을 미치는 경우.
  3. 예시:

    • 어셈블리 프로그램에서 모듈 간의 직접적인 접근.
    • goto와 같은 명령문을 사용해 한 모듈이 다른 모듈로 직접 이동.

문제점: 내용 결합은 모듈 간의 높은 의존성을 초래하여, 유지보수와 확장성을 어렵게 만듭니다.