Hãy tưởng tượng bạn phải sử dụng mã của người khác được thiết kế như hình dưới đây:
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) { /* ... */ }
}
Bây giờ hãy tưởng tượng bạn phát hiện ra rằng mã của bạn phụ thuộc vào nó trông giống như sau:
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?
}
... Và rằng bạn muốn làm cho nó dễ sử dụng hơn, đặc biệt, để loại bỏ việc sử dụng lặp đi lặp lại các tham số không cần thiết cho ứng dụng của bạn.
Được rồi, vì vậy bạn bắt đầu xây dựng một lớp chống tham nhũng.
Điều đầu tiên là đảm bảo rằng "mã chính" của bạn không tham chiếu Messy
trực tiếp. Ví dụ: bạn sắp xếp quản lý phụ thuộc theo cách cố gắng truy cập Messy
không biên dịch được.
Thứ hai, bạn tạo một mô-đun "lớp" chuyên dụng, là người duy nhất truy cập Messy
và đưa nó ra "mã chính" theo cách có ý nghĩa tốt hơn với bạn.
Mã lớp sẽ trông như sau:
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); }
}
Do đó, "mã chính" của bạn không gây rối Messy
, Reasonable
thay vào đó, sử dụng như sau:
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");
}
Lưu ý rằng vẫn còn một mớ hỗn độn lộn xộn Messy
nhưng hiện tại nó được ẩn sâu một cách hợp lý bên trong Reasonable
, làm cho "mã chính" của bạn hợp lý sạch sẽ và không có tham nhũng sẽ được đưa đến đó bằng cách sử dụng Messy
công cụ trực tiếp .
Ví dụ trên được dựa trên cách giải thích Lớp chống tham nhũng tại c2 wiki:
Nếu ứng dụng của bạn cần xử lý cơ sở dữ liệu hoặc ứng dụng khác có mô hình không mong muốn hoặc không thể áp dụng được cho mô hình bạn muốn trong ứng dụng của riêng bạn, hãy sử dụng AnticorruptionLayer để dịch sang / từ mô hình đó và của bạn.
Lưu ý ví dụ được cố ý làm đơn giản và cô đọng để giữ cho lời giải thích ngắn gọn.
Nếu bạn có một mớ hỗn độn API lớn hơn để che giấu lớp chống tham nhũng, thì cách tiếp cận tương tự cũng được áp dụng: thứ nhất, đảm bảo "mã chính" của bạn không truy cập trực tiếp vào thứ bị hỏng và thứ hai, phơi bày nó theo cách nhiều hơn thuận tiện trong bối cảnh sử dụng của bạn.
Khi "nhân rộng" lớp của bạn ngoài một ví dụ đơn giản ở trên, hãy tính đến việc làm cho API của bạn thuận tiện không nhất thiết phải là một nhiệm vụ tầm thường. Đầu tư một nỗ lực để thiết kế lớp của bạn đúng cách , xác minh mục đích sử dụng của nó với các bài kiểm tra đơn vị, v.v.
Nói cách khác, đảm bảo rằng API của bạn thực sự là một cải tiến so với API mà nó ẩn, hãy đảm bảo rằng bạn không chỉ giới thiệu một lớp tham nhũng khác.
Để hoàn thiện, hãy chú ý sự khác biệt tinh tế nhưng quan trọng giữa mẫu này và các mẫu có liên quan Bộ điều hợp và Mặt tiền . Như được chỉ định bởi tên của nó, lớp chống tham nhũng giả định rằng API cơ bản có vấn đề về chất lượng (bị "hỏng") và có ý định bảo vệ các vấn đề được đề cập.
Bạn có thể nghĩ về nó theo cách này: nếu bạn có thể biện minh rằng nhà thiết kế thư viện sẽ tốt hơn là phơi bày chức năng của nó Reasonable
thay vì Messy
, điều này có nghĩa là bạn đang làm việc trên lớp chống tham nhũng, thực hiện công việc của họ , sửa lỗi thiết kế của họ .
Trái ngược với điều đó, Adaptor và Facade không đưa ra các giả định về chất lượng của thiết kế cơ bản. Chúng có thể được áp dụng cho API được thiết kế tốt để bắt đầu, chỉ cần điều chỉnh nó cho các nhu cầu cụ thể của bạn.
Trên thực tế, thậm chí có thể hiệu quả hơn khi giả định rằng các mẫu như Adaptor và Facade mong muốn mã cơ bản được thiết kế tốt. Bạn có thể nghĩ về nó theo cách này: mã được thiết kế tốt không quá khó để điều chỉnh cho trường hợp sử dụng cụ thể. Nếu nó chỉ ra rằng thiết kế bộ điều hợp của bạn tốn nhiều công sức hơn dự kiến, điều này có thể chỉ ra rằng mã cơ bản, bằng cách nào đó, "bị lỗi". Trong trường hợp đó, bạn có thể xem xét phân tách công việc để tách các giai đoạn: trước tiên, thiết lập lớp chống tham nhũng để trình bày API cơ bản theo cách có cấu trúc đúng và tiếp theo, thiết kế bộ điều hợp / mặt tiền của bạn trên lớp bảo vệ đó.