เลเยอร์ต่อต้านการคอร์รัปชั่นคืออะไรและใช้อย่างไร


151

ฉันพยายามหาว่าเลเยอร์ต่อต้านการทุจริตนั้นหมายถึงอะไรจริงๆ ฉันรู้ว่ามันเป็นวิธีในการเปลี่ยน / แก้ไขรหัสดั้งเดิมหรือ API ที่ไม่ดี สิ่งที่ฉันไม่เข้าใจคือวิธีการทำงานและสิ่งที่ทำให้แยกจากชั้นที่ไม่พึงประสงค์

ฉันค้นหาเสร็จแล้ว แต่ฉันไม่สามารถหาตัวอย่างหรือคำอธิบายง่ายๆได้ดังนั้นฉันจึงมองหาคนที่เข้าใจและสามารถอธิบายได้ด้วยตัวอย่างง่ายๆ คำตอบที่จะตอบสนองคำถามของฉันควรจะง่าย (ไม่จำเป็นต้องสั้น) และให้ตัวอย่างที่เข้าใจการใช้งาน

ดูคำถามนี้สำหรับกรณีการใช้งานของฉัน

คำตอบ:


147

ลองนึกภาพคุณต้องใช้รหัสของคนอื่นที่ได้รับการออกแบบดังแสดงด้านล่าง:

    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?
}

... และคุณต้องการทำให้การใช้งานง่ายขึ้นโดยเฉพาะเพื่อกำจัดการใช้งานซ้ำ ๆ ของพารามิเตอร์ที่ไม่จำเป็นสำหรับแอปพลิเคชันของคุณ

เอาล่ะคุณเริ่มสร้างเลเยอร์ต่อต้านการทุจริต

  1. สิ่งแรกคือเพื่อให้แน่ใจว่า "รหัสหลัก" ของคุณไม่ได้อ้างถึงMessyโดยตรง ตัวอย่างเช่นคุณจัดการการพึ่งพาในลักษณะที่พยายามเข้าถึงMessyล้มเหลวในการรวบรวม

  2. ประการที่สองคุณสร้างโมดูล "เลเยอร์" โดยเฉพาะซึ่งเป็นหนึ่งเดียวที่เข้าถึง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สิ่งต่าง ๆ โดยตรง


ตัวอย่างข้างต้นขึ้นอยู่กับวิธีอธิบายเลเยอร์ Anticorruptionที่ c2 wiki:

หากแอปพลิเคชันของคุณต้องการจัดการกับฐานข้อมูลหรือแอปพลิเคชันอื่นที่มีโมเดลที่ไม่พึงประสงค์หรือไม่เหมาะสมกับโมเดลที่คุณต้องการภายในแอปพลิเคชันของคุณเองให้ใช้ AnticorruptionLayer เพื่อแปลเป็น / จากโมเดลนั้นและของคุณ

ตัวอย่างของโน้ตนั้นถูกสร้างขึ้นมาอย่างเรียบง่ายและย่อเพื่อให้คำอธิบายสั้น ๆ

หากคุณมีระเบียบที่ใหญ่กว่า API เพื่อปกปิดเลเยอร์ต่อต้านการคอรัปชั่นให้ใช้วิธีการเดียวกัน: ก่อนอื่นตรวจสอบให้แน่ใจว่า "รหัสหลัก" ของคุณไม่สามารถเข้าถึงสิ่งที่เสียหายได้โดยตรงและในลำดับที่สอง สะดวกในบริบทการใช้งานของคุณ

เมื่อ "ขยาย" เลเยอร์ของคุณนอกเหนือจากตัวอย่างแบบง่ายด้านบนให้คำนึงถึงว่าการทำให้ API ของคุณสะดวกไม่จำเป็นต้องเป็นเรื่องเล็กน้อย ลงทุนความพยายามในการออกแบบเลเยอร์ของคุณอย่างถูกต้องตรวจสอบการใช้งานที่ต้องการด้วยการทดสอบหน่วยฯลฯ

กล่าวอีกนัยหนึ่งตรวจสอบให้แน่ใจว่า API ของคุณได้รับการปรับปรุงให้ดีขึ้นกว่าเดิมซ่อนอยู่ตรวจสอบให้แน่ใจว่าคุณไม่ได้แนะนำการทุจริตอีกชั้นหนึ่ง


เพื่อความครบถ้วนสมบูรณ์ให้เห็นความแตกต่างบอบบาง แต่ที่สำคัญระหว่างนี้และที่เกี่ยวข้องกับรูปแบบอะแดปเตอร์และซุ้ม ตามที่ระบุโดยชื่อชั้นต่อต้านการคอร์รัปชั่นถือว่าAPI พื้นฐานมีปัญหาด้านคุณภาพ (คือ "เสียหาย") และตั้งใจที่จะให้การป้องกันปัญหาที่กล่าวถึง

คุณสามารถคิดว่าวิธีนี้ถ้าคุณสามารถแสดงให้เห็นถึงว่านักออกแบบห้องสมุดจะดีกว่าการเปิดเผยการทำงานกับReasonableแทนMessyนี้จะหมายถึงคุณกำลังทำงานบนชั้นต่อต้านการทุจริตทำของพวกเขางานการแก้ไขของพวกเขาผิดพลาดการออกแบบ

เมื่อเทียบกับที่กล่าวว่าอะแดปเตอร์และซุ้มไม่ได้ตั้งสมมติฐานเกี่ยวกับคุณภาพของการออกแบบพื้นฐาน สิ่งเหล่านี้สามารถนำไปใช้กับ API ที่ได้รับการออกแบบมาเป็นอย่างดีโดยเริ่มต้นเพียงปรับให้เหมาะกับความต้องการเฉพาะของคุณ

ที่จริงแล้วมันอาจมีประสิทธิผลมากกว่าที่จะสมมติว่ารูปแบบเช่นAdapterและFacadeคาดว่าโค้ดพื้นฐานจะได้รับการออกแบบมาอย่างดี คุณสามารถคิดได้ด้วยวิธีนี้: โค้ดที่ออกแบบมาอย่างดีไม่ควรปรับแต่งยากเกินไปสำหรับกรณีการใช้งานเฉพาะ หากปรากฎว่าการออกแบบอะแดปเตอร์ของคุณใช้ความพยายามมากกว่าที่คาดหมายนี่อาจเป็นการระบุว่ารหัสอ้างอิงนั้นเป็นอย่างใด "เสียหาย" ในกรณีดังกล่าวคุณสามารถพิจารณาแบ่งงานออกเป็นขั้นตอนต่างๆดังนี้ขั้นแรกสร้างเลเยอร์การต่อต้านการคอรัปชั่นเพื่อแสดง API พื้นฐานในโครงสร้างที่เหมาะสมและถัดไปออกแบบอะแดปเตอร์ / ส่วนหน้าของเลเยอร์การป้องกันนั้น


1
สเกลนี้มีวิธีการอย่างไรหากมีโครงสร้างทั้งหมดของคลาส API ที่ขึ้นต่อกัน มันยังสามารถจัดการได้มากกว่านี้แล้วเลเยอร์ที่ปกป้องส่วนที่เหลือของแอปพลิเคชันจะเป็นอย่างไร
knownasilya

1
@Knownasilya เป็นคำถามที่ดีมากคำตอบขยายไปยังที่อยู่นั้น
gnat

4
In other words, make sure that your API is indeed an improvement over one it hides, make sure that you don't just introduce another layer of corruption.ส่วนทั้งหมดนั้นมีค่าของแท็กตัวหนา
Lilienthal

19
เลเยอร์ต่อต้านการทุจริตนั้นไม่เกี่ยวข้องกับการจัดการกับ API คุณภาพต่ำ พวกเขากำลังจัดการกับแนวคิดที่ไม่ตรงกันการปรับโดเมนที่เราสามารถทำได้โดย "ทำให้เสียหาย" รหัสของเรากับโดเมนที่เราสามารถใช้งานได้ง่ายขึ้น
Ian Fairman

8
Ian Fairman ทำให้ถูกต้องในขณะที่ผู้เขียนคำตอบนี้ไม่ได้แน่นอนที่สุด หากคุณไปที่แหล่งที่มาของแนวคิด (หนังสือ DDD) คุณจะพบอย่างน้อยสองสิ่งที่ขัดแย้งกับคำตอบนี้: 1) เลเยอร์ต่อต้านการทุจริตถูกสร้างขึ้นเพื่อหลีกเลี่ยงการทำลายรูปแบบโดเมนใหม่ที่เรากำลังพัฒนาด้วยองค์ประกอบ จากรูปแบบของระบบภายนอกที่มีอยู่; ไม่ใช่ว่าระบบอื่น "เสียหาย" ในความเป็นจริงมันอาจดีอย่างสมบูรณ์และออกแบบมาอย่างดี 2) การต่อต้านการทุจริตชั้นมักจะมีหลายชั้นมักจะรวมถึง Facadesและอะแดปเตอร์เช่นเดียวกับบริการ
Rogério

41

หากต้องการอ้างอิงแหล่งข้อมูลอื่น:

สร้างเลเยอร์แยกเพื่อให้ลูกค้ามีฟังก์ชั่นในแง่ของรูปแบบโดเมนของตัวเอง เลเยอร์พูดคุยกับระบบอื่นผ่านทางอินเทอร์เฟซที่มีอยู่ซึ่งต้องการการปรับเปลี่ยนเล็กน้อยหรือไม่มีเลยกับระบบอื่น ภายในเลเยอร์แปลทั้งสองทิศทางตามความจำเป็นระหว่างสองรุ่น

Eric Evans, การออกแบบโดเมนขับเคลื่อน, การพิมพ์ 16, หน้า 365

สิ่งที่สำคัญที่สุดคือการใช้คำศัพท์ที่แตกต่างกันในแต่ละด้านของเลเยอร์การต่อต้านการทุจริต ฉันเคยทำงานในระบบขนส่งโลจิสติกส์ ต้องมีการวางแผนรอบ คุณต้องจัดเตรียมยานพาหนะไว้ที่คลังขับรถไปยังไซต์ลูกค้าที่แตกต่างกันและให้บริการและเยี่ยมชมสถานที่อื่น ๆ เช่นป้ายรถถัง แต่จากระดับที่สูงกว่านี่คือทั้งหมดที่เกี่ยวกับการวางแผนงาน ดังนั้นจึงเหมาะสมที่จะแยกข้อกำหนดการวางแผนงานทั่วไปออกจากข้อกำหนดโลจิสติกการขนส่งที่เฉพาะเจาะจงมาก

ดังนั้นการแยกเลเยอร์ต่อต้านการคอร์รัปชั่นไม่เพียง แต่เกี่ยวกับการปกป้องคุณจากรหัสที่ยุ่งเหยิงเท่านั้น แต่ยังเป็นการแยกโดเมนที่แตกต่างกันออกไปและทำให้แน่ใจว่าพวกเขาจะแยกจากกันในอนาคต


6
สิ่งนี้สำคัญมาก! ACL ไม่เพียง แต่จะใช้กับรหัสยุ่ง แต่เป็นวิธีการสื่อสารระหว่างบริบทที่ล้อมรอบ มันแปลจากบริบทหนึ่งไปยังอีกบริบทหนึ่งเพื่อให้ข้อมูลในแต่ละบริบทสะท้อนถึงภาษาและวิธีที่บริบทนั้นคิดและพูดคุยเกี่ยวกับข้อมูล
Didier A.

29

อะแดปเตอร์

เมื่อคุณมีอินเทอร์เฟซที่เข้ากันไม่ได้ซึ่งมีตรรกะที่คล้ายกันเพื่อปรับอินเทอร์เฟซให้เป็นอินเทอร์เฟซอื่นเพื่อให้คุณสามารถใช้งานแอพพลิเคชั่นของหนึ่งกับสิ่งที่ต้องการ

ตัวอย่าง:

คุณมีวัตถุที่ต้องการรถ แต่คุณมีคลาส 4WheelVehicle เท่านั้นดังนั้นคุณจึงสร้าง CarBuiltUsing4WheelVehicle และใช้เป็นรถของคุณ

หน้าตึก

เมื่อคุณมี API ที่ซับซ้อน / สับสน / มีขนาดใหญ่และคุณต้องการทำให้ง่ายขึ้น / ชัดเจนขึ้น / เล็กลง คุณจะสร้างซุ้มเพื่อซ่อนความซับซ้อน / ความสับสน / ความพิเศษและเปิดเผยเฉพาะ API แบบง่าย / ชัดเจน / ขนาดเล็กเท่านั้น

ตัวอย่าง:

คุณกำลังใช้ไลบรารีที่มี 100 วิธีและเพื่อทำงานบางอย่างที่คุณต้องทำในการเริ่มต้นเชื่อมต่อเปิด / ปิดสิ่งต่าง ๆ เพื่อที่จะสามารถทำสิ่งที่คุณต้องการได้ในที่สุดและสิ่งที่คุณต้องการคือ 1 คุณสมบัติของ ห้องสมุดทั้ง 50 แห่งสามารถทำได้ดังนั้นคุณจึงสร้าง Facade ที่มีวิธีการเพียง 1 อย่างสำหรับคุณสมบัติที่คุณต้องการและการเริ่มต้นทำความสะอาดและอื่น ๆ ทั้งหมดสำหรับคุณ

เลเยอร์ต่อต้านการทุจริต

เมื่อคุณมีระบบที่อยู่นอกโดเมนของคุณ แต่ความต้องการทางธุรกิจของคุณต้องการให้คุณทำงานกับโดเมนอื่นนั้น คุณไม่ต้องการที่จะแนะนำโดเมนอื่นนี้เป็นของคุณเองดังนั้นจึงทำให้เกิดความเสียหายดังนั้นคุณจะแปลแนวคิดของโดเมนของคุณเป็นโดเมนอื่นนี้และในทางกลับกัน

ตัวอย่าง:

หนึ่งระบบจะดู custumer ที่มีชื่อและรายการสตริงหนึ่งรายการสำหรับแต่ละธุรกรรม คุณดูโพรไฟล์เป็นคลาสแบบสแตนด์อโลนที่มีชื่อและธุรกรรมเป็นคลาสแบบสแตนด์อโลนที่มีสตริงและลูกค้ามีโปรไฟล์และชุดของธุรกรรม

ดังนั้นคุณจึงสร้างเลเยอร์ ACL ที่จะช่วยให้การแปลระหว่างลูกค้าของคุณและลูกค้าของระบบอื่น ๆ ด้วยวิธีนี้คุณไม่จำเป็นต้องใช้ลูกค้าของระบบอื่นคุณเพียงแค่ต้องบอก ACL: "ให้โปรไฟล์ลูกค้า X แก่ฉันและ ACL จะบอกระบบอื่นให้ลูกค้าชื่อ X.name และส่งคืน คุณเป็นลูกค้าที่มีโปรไฟล์ X

====================

ทั้งสามมีความคล้ายคลึงกันเนื่องจากเป็นรูปแบบทางอ้อมทั้งหมด แต่พวกมันพูดถึงโครงสร้างที่แตกต่างคลาส / วัตถุเทียบกับ API กับโมดูล / ระบบย่อย คุณสามารถรวมพวกมันทั้งหมดได้ถ้าคุณต้องการ ระบบย่อยมี API ที่ซับซ้อนดังนั้นคุณจึงสร้าง FACADE สำหรับมันใช้โมเดลที่แตกต่างกันดังนั้นสำหรับการแสดงข้อมูลแต่ละรายการที่ไม่เหมาะกับโมเดลของคุณคุณจะต้องแปลข้อมูลนั้นกลับไปเป็นแบบจำลอง ในที่สุดอินเทอร์เฟซอาจเข้ากันไม่ได้ดังนั้นคุณจะต้องใช้ ADAPTERS เพื่อปรับจากอันหนึ่งไปอีกอันหนึ่ง


12

คำตอบมากมายที่นี่บอกว่า ACL เป็น "ไม่ใช่แค่" เกี่ยวกับการตัดโค้ดยุ่ง ๆ ฉันจะไปต่อและบอกว่าพวกเขาไม่ได้เกี่ยวกับเรื่องนั้นเลยและถ้าพวกเขาทำเช่นนั้นนั่นเป็นผลประโยชน์ข้างเคียง

เลเยอร์ต่อต้านการทุจริตนั้นเกี่ยวกับการจับคู่หนึ่งโดเมนไปยังอีกโดเมนหนึ่งเพื่อให้บริการที่ใช้โดเมนที่สองไม่จำเป็นต้อง "เสียหาย" โดยแนวคิดจากโดเมนแรก ACL คือโมเดลของโดเมนที่อะแดปเตอร์เชื่อมต่อกับคลาส แต่เพิ่งเกิดขึ้นในระดับที่แตกต่างกัน อะแดปเตอร์นั้นเป็นรูปแบบการออกแบบที่สำคัญที่สุด - ฉันใช้มันตลอดเวลา - แต่การตัดสินว่าคลาสที่พันแล้วนั้นยุ่งหรือไม่มีความเกี่ยวข้อง มันคือสิ่งที่มันเป็นฉันแค่ต้องการมันมีอินเตอร์เฟซที่แตกต่างกัน

การเพ่งความสนใจไปที่ความยุ่งเหยิงนั้นทำให้เข้าใจผิดและคิดถึงจุดที่ DDD เกี่ยวข้อง ACLs เกี่ยวกับการจัดการกับแนวคิดที่ไม่ตรงกันไม่ใช่คุณภาพต่ำ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.