Уявіть, що вам потрібно використовувати чужий код, розроблений, як показано нижче:
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:
Якщо вашій програмі потрібно мати справу з базою даних або іншою програмою, модель якої небажана або не застосовується до моделі, яку ви хочете, у вашій власній програмі, використовуйте антикорупційний шар для перекладу на / з цієї моделі та вашої.
Приклад примітки навмисно робиться простим і стислим, щоб пояснення були короткими.
Якщо у вас є більший безлад API, який слід покрити за антикорупційним шаром, застосовується той же підхід: по-перше, переконайтеся, що ваш "основний код" не отримує доступ до пошкоджених матеріалів безпосередньо, а по-друге, викрийте його таким чином, що більше зручна у вашому контексті використання.
Під час "масштабування" шару за спрощеним прикладом, який вище, врахуйте, що зробити API зручним - це не обов'язково тривіальне завдання. Вкладіть зусилля, щоб правильно розробити ваш шар , перевірити його використання за допомогою модульних тестів тощо.
Іншими словами, переконайтеся, що ваш API справді є поліпшенням порівняно з одним, який він приховує, переконайтеся, що ви не просто вводите інший шар корупції.
Для повноти зауважте тонку, але важливу різницю між цим та відповідними шаблонами Адаптер та Фасад . Як вказується його назва, антикорупційна шар передбачає , що базовий API має проблеми з якістю (як «пошкоджений») і має намір запропонувати захист зазначених питань.
Ви можете думати про це так: якщо ви можете обґрунтувати , що бібліотека дизайнер буде краще виставляючи його функціональність з Reasonable
замість Messy
, це буде означати, що ви працюєте на антикорупційному шарі, роблячи їх роботу, фіксуючи свої дизайнерські помилки.
На відміну від цього, адаптер та фасад не роблять припущень щодо якості базового дизайну. Вони можуть бути застосовані до API, який добре розроблений для початку, просто адаптуючи його до ваших конкретних потреб.
Насправді, може бути навіть більш продуктивним припустити, що такі моделі, як Адаптер та Фасад, очікують, що базовий код буде добре розроблений. Ви можете подумати про це так: добре розроблений код не повинен бути занадто складним для підключення для конкретного випадку використання. Якщо виявиться, що дизайн вашого адаптера вимагає більше зусиль, ніж очікувалося, це може означати, що базовий код, ну, якимось чином "пошкоджений". У такому випадку ви можете розглянути завдання розділити завдання на окремі фази: спочатку встановіть антикорупційний шар, щоб представити базовий API правильно структурованим способом, а далі, спроектуйте адаптер / фасад на цей захисний шар.