아래와 같이 설계된 다른 사람의 코드를 사용해야한다고 상상해보십시오.
class Messy {
String concat(String param, String str) { /* ... */ }
boolean contains(String param, String s) { /* ... */ }
boolean isEmpty(String param) { /* ... */ }
boolean matches(String param, String regex) { /* ... */ }
boolean startsWith(String param, String prefix) { /* ... */ }
}
이제 코드에 의존하는 코드가 다음과 같다는 것을 알게됩니다.
String process(String param) {
Messy messy = new Messy();
if (messy.contains(param, "whatever")) {
return messy.concat(param, "-contains");
}
if (messy.isEmpty(param)) {
return messy.concat(param, "-empty");
}
if (messy.matches(param, "[whatever]")) {
return messy.concat(param, "-matches");
}
if (messy.startsWith(param, "whatever")) {
return messy.concat(param, "-startsWith");
}
return messy.concat(param, "-whatever");
// WTF do I really need to repeat bloody "param" 9 times above?
}
... 특히 응용 프로그램에 필요하지 않은 반복적 인 매개 변수 사용을 없애기 위해 더 쉽게 사용할 수 있기를 원합니다.
자, 반부패 계층을 구축하기 시작합니다.
먼저 "메인 코드"가 Messy
직접 참조되지 않는지 확인하십시오 . 예를 들어 액세스 시도 가 컴파일되지 않는 방식으로 종속성 관리 를 정렬 Messy
합니다.
둘째, 액세스하는 유일한 "전용 레이어"모듈을 만들어서 Messy
"메인 코드"에보다 적합한 방식으로 노출시킵니다.
레이어 코드는 다음과 같습니다.
class Reasonable { // anti-corruption layer
String param;
Messy messy = new Messy();
Reasonable(String param) {
this.param = param;
}
String concat(String str) { return messy.concat(param, str); }
boolean contains(String s) { return messy.contains(param, s); }
boolean isEmpty() { return messy.isEmpty(param); }
boolean matches(String regex) { return messy.matches(param, regex); }
boolean startsWith(String prefix) { return messy.startsWith(param, prefix); }
}
결과적으로, "메인 코드"는 다음과 같이 대신에를 Messy
사용하여 엉망이되지 않습니다 Reasonable
.
String process(String param) {
Reasonable reasonable = new Reasonable(param);
// single use of "param" above and voila, you're free
if (reasonable.contains("whatever")) {
return reasonable.concat("-contains");
}
if (reasonable.isEmpty()) {
return reasonable.concat("-empty");
}
if (reasonable.matches("[whatever]")) {
return reasonable.concat("-matches");
}
if (reasonable.startsWith("whatever")) {
return reasonable.concat("-startsWith");
}
return reasonable.concat("-whatever");
}
여전히 엉망인 약간의 혼란 Messy
이 있지만 이것은 이제 상당히 깊숙이 숨겨져 Reasonable
있어 "메인 코드"를 합리적으로 깨끗하고 손상시키지 않고 Messy
물건 을 직접 사용하여 가져올 수 있습니다 .
위의 예는 c2 wiki에서 반부패 계층 이 설명되는 방식을 기반으로합니다 .
응용 프로그램이 데이터베이스 또는 모델이 바람직하지 않거나 자신의 응용 프로그램 내에서 원하는 모델에 적용 할 수없는 다른 응용 프로그램을 처리해야하는 경우 AnticorruptionLayer를 사용하여 해당 모델과 사용자의 데이터베이스간에 변환합니다.
참고 예는 설명을 간단하게하기 위해 의도적으로 단순하고 요약 된 것입니다.
반부패 계층 뒤에서 다루기 위해 더 큰 API 엉망이있는 경우 동일한 접근 방식이 적용됩니다. 먼저 "주 코드"가 손상된 항목에 직접 액세스하지 않는지 확인하십시오. 사용 환경에서 편리합니다.
위의 간단한 예제를 넘어서 레이어를 "스케일링"할 때 API를 편리하게 만드는 것이 사소한 작업이 아니라는 점을 고려하십시오. 올바른 방법으로 레이어 를 설계 하고 단위 테스트 등을 통해 의도 된 용도를 확인하기위한 노력 을 투자 하십시오 .
다시 말해, API가 실제로 숨겨 지는 API 보다 개선 된 것인지 확인하고 다른 손상 계층을 도입하지 않아야합니다.
완벽을 기하기 위해이 패턴과 관련 패턴 인 어댑터 및 외관 사이의 미묘하지만 중요한 차이점에 주목하십시오 . 그 이름으로 표시된 바와 같이, 부패 방지 계층은 기본 API에 품질 문제 ( "손상됨")가 있으며 언급 된 문제의 보호를 제공하려고합니다.
당신은 그것을 이런 식으로 생각할 수 있습니다 : 당신이 그 기능을 노출 더 나을 것이라고 라이브러리 디자이너를 정당화 할 수있는 경우 Reasonable
대신 Messy
, 이것은 당신이, 반부패 층에서 작업하고있는 의미 자신의 일을, 고정 자신의 디자인 실수를.
이에 반해 Adapter and Facade 는 기본 디자인의 품질을 가정하지 않습니다. 이것들은 특정 요구에 맞게 조정하여 시작하도록 잘 설계된 API에 적용될 수 있습니다.
실제로 Adapter 및 Facade 와 같은 패턴이 기본 코드가 잘 설계 되어 있다고 가정하는 것이 더 생산적 일 수 있습니다. 잘 설계된 코드는 특정 사용 사례를 조정하기가 너무 어렵지 않아야합니다. 어댑터 설계에 예상보다 많은 노력이 소요되는 경우 기본 코드가 "손상된"것일 수 있습니다. 이 경우 작업을 별도의 단계로 분할하는 것을 고려할 수 있습니다. 먼저, 기본 API를 올바르게 구조화 된 방식으로 표시하기 위해 반부패 계층을 설정 한 다음 해당 보호 계층 위에 어댑터 / 파사드를 설계하십시오.