พร็อกซีมัณฑนากรอะแดปเตอร์และรูปแบบบริดจ์แตกต่างกันอย่างไร


403

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


4
มักจะมีรูปแบบที่มีลักษณะคล้ายกันมาก แต่มีความตั้งใจแตกต่างกัน (กลยุทธ์และรูปแบบของรัฐอยู่ในใจ) ฉันคิดว่านี่เป็นเพราะความจริงที่ว่ารูปแบบการออกแบบเป็นไปตามหลักการออกแบบที่เป็นของแข็งทั่วไป
23499 Jason Jason Down

5
รูปแบบทั้งสี่นี้มีรายละเอียดการใช้งานที่เหมือนกันทุกประการ อย่างน้อยที่สุดข้อสรุปของรัฐสามารถสรุปได้ว่าเป็นบทกลอนของรัฐที่ไร้รัฐ (ส่วนใหญ่) บ่อยครั้งที่กลยุทธ์เป็นเพียงวิธีการฉีดซึ่งรูปแบบของรัฐใช้อินเทอร์เฟซเพื่อทำมากกว่าการเรียกวิธีการที่เป็นนามธรรม กลยุทธ์ในตอนท้ายของวันนั้นเป็นแฮ็คที่อนุญาตให้มีการเขียนโปรแกรมที่ใช้งานได้ในโลกของ OO
ชาร์ลส์เกรแฮม

คำตอบ:


648

พร็อกซีมัณฑนากรอะแดปเตอร์และบริดจ์เป็นรูปแบบทั้งหมดของการ "ตัด" คลาส แต่การใช้งานของพวกเขาแตกต่างกัน

  • สามารถใช้พร็อกซีเมื่อคุณต้องการยกตัวอย่างวัตถุหรือซ่อนความจริงที่ว่าคุณกำลังเรียกใช้บริการระยะไกลหรือควบคุมการเข้าถึงวัตถุ

  • มัณฑนากรเรียกอีกอย่างว่า "Smart Proxy" ใช้เมื่อคุณต้องการเพิ่มฟังก์ชันการทำงานกับวัตถุ แต่ไม่ใช่โดยการขยายประเภทของวัตถุนั้น สิ่งนี้อนุญาตให้คุณทำตอนรันไทม์

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

  • Bridgeนั้นคล้ายกับ Adapter แต่เราเรียกมันว่า Bridge เมื่อคุณกำหนดทั้ง interface นามธรรมและการใช้งานพื้นฐาน เช่นคุณไม่ได้ปรับตัวให้เข้ากับรหัสดั้งเดิมหรือของบุคคลที่สามคุณเป็นผู้ออกแบบรหัสทั้งหมด แต่คุณต้องสามารถสลับการใช้งานที่แตกต่างกันได้

  • Facadeเป็นอินเตอร์เฟสระดับสูงกว่า (อ่าน: เรียบง่าย) ไปยังระบบย่อยของหนึ่งคลาสขึ้นไป สมมติว่าคุณมีแนวคิดที่ซับซ้อนที่ต้องใช้วัตถุหลายรายการเพื่อเป็นตัวแทน การเปลี่ยนแปลงชุดของวัตถุนั้นทำให้เกิดความสับสนเนื่องจากคุณไม่ทราบว่าวัตถุใดมีวิธีที่คุณต้องเรียก นั่นเป็นเวลาที่จะเขียน Facade ที่ให้วิธีการระดับสูงสำหรับการดำเนินการที่ซับซ้อนทั้งหมดที่คุณสามารถทำได้ในการรวบรวมวัตถุ ตัวอย่าง: รุ่นโดเมนสำหรับส่วนโรงเรียนที่มีวิธีการเช่นcountStudents(), reportAttendance(), assignSubstituteTeacher()และอื่น ๆ


7
คำตอบที่ดี. อาจจะมีมูลค่าเพิ่มตัวอย่างบางส่วนของที่คุณเห็นในป่า? เช่นคลาส Proxy ใน Web Services +1 จากฉัน
Rob Cooper

5
@ Rob: ขอบคุณ แต่ฉันอยากให้คำตอบนี้สั้นและหวาน ฉันขอแนะนำให้คุณเขียนคำตอบด้วยตัวอย่างในป่า!
Bill Karwin

8
@RobertDailey Decorator เป็นสิ่งที่ดีที่จะหลีกเลี่ยงลำดับชั้นชนิดการควบคุม ตัวอย่างเช่นสมมติว่าคุณมีหน้าต่างใน GUI และคุณต้องการมีแถบเลื่อนเสริม คุณสามารถมีคลาส Window, VScrollWindow, HScrollWindow และ VHScrollWindow หรือคุณสามารถสร้างตกแต่ง VScroll และ HScroll บน Window
Eva

1
@RobertDailey ผู้ตกแต่งเป็นองค์ประกอบ
Bill Karwin

1
และถ้าคุณต้องการทำซ้ำอินเทอร์เฟซของวัตถุที่ถูกห่อ 1: 1 แล้วเพิ่มวิธีการเพิ่มเติมสักสองสามอัน? นี่คือมัณฑนากรหรืออะแดปเตอร์หรือไม่?
donquixote

198

เป็นคำตอบของบิลกล่าวว่ากรณีการใช้งานที่แตกต่างกัน

ดังนั้นโครงสร้างของพวกเขา

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

  • อะแดปเตอร์และซุ้มทั้งสองมีอินเตอร์เฟซที่แตกต่างจากสิ่งที่พวกเขาห่อ แต่อะแดปเตอร์นั้นมาจากอินเทอร์เฟซที่มีอยู่ในขณะที่ซุ้มสร้างอินเทอร์เฟซใหม่

  • BridgeและAdaptorทั้งสองชี้ไปที่ชนิดที่มีอยู่ แต่บริดจ์จะชี้ไปที่รูปแบบนามธรรมและอะแดปเตอร์อาจชี้ไปที่ประเภทที่เป็นรูปธรรม บริดจ์จะอนุญาตให้คุณจับคู่การนำไปใช้งานที่รันไทม์ในขณะที่อะแดปเตอร์มักจะไม่


30
คำตอบของคุณรวมกับ Bill's รวบรวมลวดลายการออกแบบ 5 บทเป็นอย่างดี เราสามารถเรียกพวกเขาว่าอินเทอร์เฟซระดับสูงกว่า (อ่าน: เรียบง่าย) กับหนังสือ
Jonas Eicher

54

ฉันใช้เวลาในเรื่อง

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

โดยการส่งเสริมการมีเพศสัมพันธ์แบบหลวมพวกเขาทำให้รหัสที่เสถียรน้อยลงเมื่อมีการเปลี่ยนแปลงที่หลีกเลี่ยงไม่ได้และสามารถอ่านได้ดีขึ้นสำหรับนักพัฒนาซอฟต์แวร์

อะแดปเตอร์

อะแดปเตอร์จะปรับหัวเรื่อง (adaptee) ให้เป็นอินเตอร์เฟสที่ต่างกัน วิธีนี้เราสามารถเพิ่มวัตถุถูกวางลงในคอลเลกชันประเภทที่แตกต่างกันในนาม

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

อะแดปเตอร์ป้องกันหนึ่งทีมจากโค้ดระเหยจากทีมอื่น เครื่องมือช่วยชีวิตเมื่อต้องรับมือกับทีมนอกชายฝั่ง ;-)

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

อะแด็ปเตอร์ช่วยในการหลีกเลี่ยงข้อ จำกัด Java ของการสืบทอดเดียวเท่านั้น มันสามารถรวมหลาย adaptees ภายใต้ซองเดียวให้แสดงผลของการสืบทอดหลาย

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

ไม่มีตัวอย่างอะแดปเตอร์ที่ดีจำนวนมากใน JDK หรือไลบรารีพื้นฐาน นักพัฒนาแอปพลิเคชันสร้างอะแดปเตอร์เพื่อปรับไลบรารีให้เข้ากับอินเตอร์เฟสเฉพาะของแอปพลิเคชัน

มัณฑนากร

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

โดยทั่วไปมัณฑนากรจะเพิ่มฟังก์ชัน (โปร่งใส) ให้กับวัตถุที่ถูกห่อเช่นการบันทึกการเข้ารหัสการจัดรูปแบบหรือการบีบอัดให้กับวัตถุ ฟังก์ชั่นใหม่นี้อาจมีรหัสใหม่มากมาย ดังนั้นนักตกแต่งมักจะ“ อ้วนขึ้น” มากแล้วอะแดปเตอร์

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

ตัวอย่างหนังสือเรียนของตระกูลมัณฑนากรทั้งคู่นั้นพร้อมใน JDK - Java IO ทุกชั้นเรียนเช่นBufferedOutputStream , FilterOutputStreamและObjectOutputStreamเป็นของตกแต่งOutputStream พวกเขาสามารถเป็นชั้นหัวหอมที่หนึ่งในมัณฑนากรได้รับการตกแต่งอีกครั้งเพิ่มการทำงานมากขึ้น

หนังสือมอบฉันทะ

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

ตัวอย่างทั่วไปส่วนใหญ่เป็นพร็อกซีระยะไกลวัตถุเริ่มต้นหนักและการเข้าถึงพร็อกซี่

  • รีโมตพร็อกซี - หัวเรื่องอยู่บนเซิร์ฟเวอร์ระยะไกล, JVM อื่นหรือแม้แต่ระบบที่ไม่ใช่ Java พร็อกซีแปลการเรียกใช้เมธอดไปที่การเรียก RMI / REST / SOAP หรือสิ่งที่จำเป็นเพื่อป้องกันไคลเอ็นต์จากการสัมผัสกับเทคโนโลยีพื้นฐาน

  • Lazy Load Proxy - เริ่มต้นวัตถุอย่างสมบูรณ์เฉพาะการใช้งานครั้งแรกหรือการใช้งานครั้งแรกอย่างเข้มข้น

  • Access Proxy - ควบคุมการเข้าถึงหัวเรื่อง

หน้าตึก

ซุ้มมีความสัมพันธ์อย่างใกล้ชิดกับหลักการออกแบบน้อยที่สุด (กฎหมายของ Demeter) ซุ้มมีลักษณะคล้ายกับอะแดปเตอร์ พวกเขาทั้งสองห่อพวกเขาทั้งคู่ทำแผนที่วัตถุหนึ่งไปยังอีกวัตถุหนึ่ง แต่พวกเขาต่างกันในเจตนา ซุ้มแบนโครงสร้างที่ซับซ้อนของวัตถุกราฟวัตถุที่ซับซ้อนทำให้การเข้าถึงโครงสร้างที่ซับซ้อนง่ายขึ้น

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

สะพาน

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

ความแตกต่างในการก่อสร้าง

ความแตกต่างของรูปแบบก็ชัดเจนเมื่อดูที่ตัวสร้าง

  • พร็อกซีไม่ได้ห่อวัตถุที่มีอยู่ ไม่มีหัวเรื่องในตัวสร้าง

  • มัณฑนากรและอะแดปเตอร์ไม่ห่อวัตถุที่มีอยู่แล้วและโดยทั่วไปแล้วจะ
    มีอยู่ในตัวสร้าง

  • ตัวสร้างFacadeใช้องค์ประกอบรากของกราฟวัตถุทั้งหมดมิฉะนั้นจะดูเหมือนอะแดปเตอร์

ตัวอย่างชีวิตจริง - JAXB Marshalling อะแดปเตอร์ วัตถุประสงค์ของอะแดปเตอร์นี้คือการแมปคลาสแบบเรียบง่ายไปยังโครงสร้างที่ซับซ้อนกว่าที่ต้องการจากภายนอกและเพื่อป้องกันไม่ให้คลาสหัวเรื่อง "สร้างมลพิษ" ด้วยคำอธิบายประกอบที่มากเกินไป


30

มีการทับซ้อนกันในรูปแบบ GoF หลายรูปแบบ พวกมันทั้งหมดถูกสร้างขึ้นด้วยพลังของความหลากหลายและบางครั้งก็มีเจตนาที่แตกต่างกัน (กลยุทธ์กับรัฐ)

ความเข้าใจของฉันของรูปแบบการเพิ่มขึ้น 100 เท่าหลังจากที่ได้อ่านรูปแบบการออกแบบหัวแรก

ฉันขอแนะนำ!


9

คำตอบที่ดีทั้งหมดจากผู้เชี่ยวชาญได้อธิบายแล้วว่าแต่ละรูปแบบหมายถึงอะไร

ฉันจะตกแต่งจุดสำคัญ

มัณฑนากร:

  1. เพิ่มพฤติกรรมไปยังวัตถุในเวลาทำงาน การสืบทอดเป็นกุญแจสำคัญในการบรรลุฟังก์ชั่นนี้ซึ่งเป็นทั้งข้อดีและข้อเสียของรูปแบบนี้
  2. มันปรับเปลี่ยนพฤติกรรมของอินเตอร์เฟซ

เช่น (พร้อมกับการผูกมัด): java.ioคลาสแพ็กเกจที่เกี่ยวข้องกับInputStream& OutputStreamอินเตอร์เฟส

FileOutputStream fos1 = new FileOutputStream("data1.txt");  
ObjectOutputStream out1 = new ObjectOutputStream(fos1);

พร็อกซี:

  1. ใช้สำหรับการเริ่มต้นขี้เกียจในการปรับปรุงประสิทธิภาพการทำงานโดยแคชวัตถุและการควบคุมการเข้าถึงไคลเอ็นต์ / โทร มันอาจมีพฤติกรรมทางเลือกหรือเรียกวัตถุจริง ในระหว่างกระบวนการนี้มันอาจสร้างวัตถุใหม่
  2. แตกต่างจากมัณฑนากรซึ่งอนุญาตให้ผูกมัดวัตถุพร็อกซีไม่อนุญาตให้ผูกมัด

เช่นjava.rmiคลาสแพ็คเกจ

อะแดปเตอร์:

  1. อนุญาตให้สองอินเตอร์เฟสที่ไม่เกี่ยวข้องทำงานร่วมกันผ่านวัตถุต่าง ๆซึ่งอาจมีบทบาทเดียวกัน
  2. มันปรับเปลี่ยนอินเตอร์เฟซที่เดิม

เช่นjava.io.InputStreamReader( InputStreamคืน a Reader)

สะพาน:

  1. จะช่วยให้ทั้งนามธรรมและการใช้งานแตกต่างกันไปอย่างอิสระ
  2. จะใช้องค์ประกอบมรดก

java.utilชั้นเรียนเช่นการเก็บใน ดำเนินการโดยListArrayList

หมายเหตุสำคัญ:

  1. อะแดปเตอร์ให้อินเทอร์เฟซที่แตกต่างกันกับเรื่องของมัน Proxyจัดเตรียมอินเตอร์เฟสเดียวกัน มัณฑนากรมอบส่วนต่อประสานที่ได้รับการปรับปรุง
  2. อะแดปเตอร์เปลี่ยนอินเทอร์เฟซของวัตถุมัณฑนากรช่วยเพิ่มความรับผิดชอบของวัตถุ
  3. มัณฑนากรและพร็อกซี่มีวัตถุประสงค์ที่แตกต่างกัน แต่โครงสร้างที่คล้ายกัน
  4. อะแดปเตอร์ทำให้สิ่งต่างๆทำงานได้หลังจากที่ออกแบบมา สะพานทำให้พวกเขาทำงานก่อนพวกเขา
  5. Bridgeได้รับการออกแบบล่วงหน้าเพื่อให้สิ่งที่เป็นนามธรรมและการนำไปปฏิบัตินั้นแตกต่างกันอย่างอิสระ อะแดปเตอร์ถูกดัดแปลงเพื่อให้ชั้นเรียนที่ไม่เกี่ยวข้องกับการทำงานร่วมกัน
  6. มัณฑนากรได้รับการออกแบบมาเพื่อให้คุณเพิ่มความรับผิดชอบให้กับวัตถุโดยไม่มีคลาสย่อย

ดูคำถาม / บทความ SE ที่ยอดเยี่ยมเกี่ยวกับตัวอย่างของรูปแบบการออกแบบที่หลากหลาย

เมื่อใดที่จะใช้รูปแบบมัณฑนากร?

คุณใช้รูปแบบบริดจ์เมื่อใด มันแตกต่างจากรูปแบบของอะแดปเตอร์อย่างไร

ความแตกต่างระหว่างพร็อกซีและรูปแบบมัณฑนากร


8

พวกมันค่อนข้างคล้ายกันและเส้นแบ่งระหว่างพวกมันค่อนข้างเทา ฉันขอแนะนำให้คุณอ่านรายการรูปแบบพร็อกซีและรูปแบบมัณฑนากรใน c2 wiki

รายการและการอภิปรายมีค่อนข้างกว้างขวางและพวกเขายังเชื่อมโยงไปยังบทความที่เกี่ยวข้องอื่น ๆ โดยวิธีการที่ wiki c2 เป็นเลิศเมื่อสงสัยเกี่ยวกับความแตกต่างระหว่างรูปแบบที่แตกต่างกัน

เพื่อรวมรายการ c2 ขึ้นฉันจะบอกว่ามัณฑนากรเพิ่ม / เปลี่ยนพฤติกรรม แต่พร็อกซีมีส่วนเกี่ยวข้องกับการควบคุมการเข้าถึง (การสร้างอินสแตนซ์ขี้เกียจการเข้าถึงจากระยะไกลความปลอดภัย ฯลฯ ) แต่อย่างที่ฉันบอกว่าเส้นแบ่งระหว่างพวกเขาเป็นสีเทาและฉันเห็นการอ้างอิงถึงพร็อกซีที่สามารถดูได้อย่างง่ายดายว่าเป็นผู้ตกแต่งและในทางกลับกัน


4

ทั้งสี่รูปแบบเกี่ยวข้องกับการห่อวัตถุภายใน / คลาสด้วยรูปภายนอกดังนั้นจึงมีโครงสร้างคล้ายกันมาก ฉันจะร่างความแตกต่างตามวัตถุประสงค์:

  • พร็อกซีห่อหุ้มการเข้าถึงในภายนอกสู่ภายใน
  • มัณฑนากรปรับเปลี่ยนหรือขยายพฤติกรรมด้านในกับด้านนอก
  • อะแดปเตอร์แปลงอินเตอร์เฟสจากภายในสู่ภายนอก
  • Bridgeแยกส่วนที่คงที่ของพฤติกรรม (ด้านนอก) จากตัวแปรหรือส่วนที่ขึ้นกับแพลตฟอร์ม (ด้านใน)

และด้วยรูปแบบอินเตอร์เฟสระหว่างวัตถุภายในและภายนอก:

  • ในอินเตอร์เฟสพร็อกซีเหมือนกัน
  • ในอินเทอร์เฟซของมัณฑนากรเหมือนกัน
  • ในอะแดปเตอร์อินเตอร์เฟสนั้นแตกต่างกันอย่างเป็นทางการ แต่ทำตามวัตถุประสงค์เดียวกัน
  • ในส่วนต่อประสานบริดจ์จะแตกต่างกันตามแนวคิด

4

นี่คือคำพูดจาก รูปแบบการออกแบบหัวแรก

คำจำกัดความเป็นของหนังสือ ตัวอย่างเป็นของฉัน

มัณฑนากร - ไม่เปลี่ยนอินเทอร์เฟซ แต่เพิ่มความรับผิดชอบ สมมติว่าคุณมีอินเทอร์เฟซสำหรับรถยนต์เมื่อคุณใช้สิ่งนี้กับรถยนต์รุ่นอื่น (s, sv, sl) คุณอาจจำเป็นต้องเพิ่มความรับผิดชอบมากขึ้นสำหรับบางรุ่น ชอบซันรูฟถุงลมนิรภัย ฯลฯ

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

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

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


1

ฉันใช้บ่อยเมื่อใช้บริการเว็บ รูปแบบพร็อกซีน่าจะถูกเปลี่ยนชื่อเป็นบางสิ่งบางอย่างในทางปฏิบัติเช่น 'Wrapper Pattern "ฉันยังมีไลบรารี่ที่เป็น Proxy to MS Excel มันทำให้การทำ Excel อัตโนมัติเป็นเรื่องง่ายโดยไม่ต้องกังวลเกี่ยวกับรายละเอียดพื้นหลังเช่น ติดตั้งเวอร์ชั่น (ถ้ามี)


นั่นจะไม่ใช่รูปแบบของอะแดปเตอร์ใช่ไหม
Charles Graham

1
พร็อกซีบริการเว็บจะถูกใช้งานในขณะที่รูปแบบของอะแดปเตอร์ถูกใช้มากขึ้นสำหรับการแปลงหรือการแปลข้อมูลจากรูปแบบหนึ่งไปเป็นอีกรูปแบบหนึ่ง
hmcclungiii

1

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

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

อีกอย่างหนึ่งพร็อกซีทำสิ่งที่เป้าหมายทำในขณะที่รูปแบบอื่น ๆ เพิ่มฟังก์ชันการทำงานให้กับเป้าหมายมากขึ้น


1

ฉันต้องการเพิ่มตัวอย่างในคำตอบของ Bill Karwing (ซึ่งยอดเยี่ยม btw.) ฉันยังเพิ่มความแตกต่างที่สำคัญบางส่วนของการใช้งานซึ่งฉันรู้สึกว่าขาดหายไป

ส่วนที่อ้างถึงมาจากคำตอบของ [ https://stackoverflow.com/a/350471/1984346] (Bill Karwing)

พร็อกซีมัณฑนากรอะแดปเตอร์และบริดจ์เป็นรูปแบบทั้งหมดของการ "ตัด" คลาส แต่การใช้งานของพวกเขาแตกต่างกัน

  • สามารถใช้พร็อกซีเมื่อคุณต้องการยกตัวอย่างวัตถุหรือซ่อนความจริงที่ว่าคุณกำลังเรียกใช้บริการระยะไกลหรือควบคุมการเข้าถึงวัตถุ

ProxyClass และ ObjectClass ที่เป็นพร็อกซีควรใช้อินเตอร์เฟสเดียวกันดังนั้นจึงสามารถเปลี่ยนได้

ตัวอย่าง - วัตถุแพงพร็อกซี

class ProxyHumanGenome implements GenomeInterface  {
    private $humanGenome = NULL; 

    // humanGenome class is not instantiated at construct time
    function __construct() {
    }

    function getGenomeCount() {
        if (NULL == $this->humanGenome) {
            $this->instantiateGenomeClass(); 
        }
        return $this->humanGenome->getGenomeCount();
    }
} 
class HumanGenome implement GenomeInterface { ... }
  • มัณฑนากรเรียกอีกอย่างว่า "Smart Proxy" ใช้เมื่อคุณต้องการเพิ่มฟังก์ชันการทำงานกับวัตถุ แต่ไม่ใช่โดยการขยายประเภทของวัตถุนั้น สิ่งนี้อนุญาตให้คุณทำตอนรันไทม์

DecoratorClass ควร (สามารถ) ใช้อินเตอร์เฟสเพิ่มเติมของ ObjectClass ดังนั้น ObjectClass สามารถถูกแทนที่ด้วย DecoratorClass แต่ไม่ใช่ในทางกลับกัน

ตัวอย่าง - เพิ่มฟังก์ชันการทำงานเพิ่มเติม

class DecoratorHumanGenome implements CheckGenomeInterface  {

    // ... same code as previous example

    // added functionality
    public function isComplete() {
        $this->humanGenome->getCount >= 21000
    }
}

interface CheckGenomeInterface extends GenomeInterface {

    public function isComplete();

}

class HumanGenome implement GenomeInterface { ... }
  • ใช้อะแดปเตอร์เมื่อคุณมีอินเทอร์เฟซแบบนามธรรมและคุณต้องการแมปอินเทอร์เฟซนั้นกับวัตถุอื่นซึ่งมีหน้าที่การทำงานคล้ายกัน แต่เป็นอินเทอร์เฟซที่แตกต่างกัน

ความแตกต่างโดยนัยของพร็อกซีมัณฑนากรอะแดปเตอร์

อะแดปเตอร์ให้อินเทอร์เฟซที่แตกต่างกับเรื่องของมัน Proxy จัดเตรียมอินเตอร์เฟสเดียวกัน มัณฑนากรมอบส่วนต่อประสานที่ได้รับการปรับปรุง

  • Bridgeนั้นคล้ายกับ Adapter แต่เราเรียกมันว่า Bridge เมื่อคุณกำหนดทั้ง interface นามธรรมและการใช้งานพื้นฐาน เช่นคุณไม่ได้ปรับตัวให้เข้ากับรหัสดั้งเดิมหรือของบุคคลที่สามคุณเป็นผู้ออกแบบรหัสทั้งหมด แต่คุณต้องสามารถสลับการใช้งานที่แตกต่างกันได้

  • Facadeเป็นอินเตอร์เฟสระดับสูงกว่า (อ่าน: เรียบง่าย) ไปยังระบบย่อยของหนึ่งคลาสขึ้นไป สมมติว่าคุณมีแนวคิดที่ซับซ้อนที่ต้องใช้วัตถุหลายรายการเพื่อเป็นตัวแทน การเปลี่ยนแปลงชุดของวัตถุนั้นทำให้เกิดความสับสนเนื่องจากคุณไม่ทราบว่าวัตถุใดมีวิธีที่คุณต้องเรียก นั่นเป็นเวลาที่จะเขียน Facade ที่ให้วิธีการระดับสูงสำหรับการดำเนินการที่ซับซ้อนทั้งหมดที่คุณสามารถทำได้ในการรวบรวมวัตถุ ตัวอย่าง: รุ่นโดเมนสำหรับส่วนโรงเรียนที่มีวิธีการเช่นcountStudents(), reportAttendance(), assignSubstituteTeacher()และอื่น ๆ

ข้อมูลส่วนใหญ่ในคำตอบนี้มาจากhttps://sourcemaking.com/design_patternsซึ่งฉันแนะนำว่าเป็นแหล่งข้อมูลที่ยอดเยี่ยมสำหรับรูปแบบการออกแบบ


0

ฉันเชื่อว่ารหัสจะให้ความคิดที่ชัดเจน (เพื่อเติมเต็มคำตอบของผู้อื่นด้วย) โปรดดูด้านล่าง (เน้นประเภทที่คลาสใช้และแรป)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            /* Proxy */

            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("PROXY");
            Console.WriteLine(Environment.NewLine);

            //instead of creating here create using a factory method, the facory method will return the proxy
            IReal realProxy = new RealProxy();
            Console.WriteLine("calling do work with the proxy object ");
            realProxy.DoWork();

            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("ADAPTER");
            Console.WriteLine(Environment.NewLine);

            /*Adapter*/
            IInHand objectIHave = new InHand();
            Api myApi = new Api();
            //myApi.SomeApi(objectIHave); /*I cant do this, use a adapter then */
            IActual myAdaptedObject = new ActualAdapterForInHand(objectIHave);
            Console.WriteLine("calling api with  my adapted obj");
            myApi.SomeApi(myAdaptedObject);


            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("DECORATOR");
            Console.WriteLine(Environment.NewLine);

            /*Decorator*/
            IReady maleReady = new Male();
            Console.WriteLine("now male is going to get ready himself");
            maleReady.GetReady();

            Console.WriteLine(Environment.NewLine);

            IReady femaleReady = new Female();
            Console.WriteLine("now female is going to get ready her self");
            femaleReady.GetReady();

            Console.WriteLine(Environment.NewLine);

            IReady maleReadyByBeautician = new Beautician(maleReady);
            Console.WriteLine("now male is going to get ready by beautician");
            maleReadyByBeautician.GetReady();

            Console.WriteLine(Environment.NewLine);

            IReady femaleReadyByBeautician = new Beautician(femaleReady);
            Console.WriteLine("now female is going to get ready by beautician");
            femaleReadyByBeautician.GetReady();

            Console.WriteLine(Environment.NewLine);

            Console.ReadLine();


        }
    }

    /*Proxy*/

    public interface IReal
    {
        void DoWork();
    }

    public class Real : IReal
    {
        public void DoWork()
        {
            Console.WriteLine("real is doing work ");
        }
    }


    public class RealProxy : IReal
    {
        IReal real = new Real();

        public void DoWork()
        {
            real.DoWork();
        }
    }

    /*Adapter*/

    public interface IActual
    {
        void DoWork();
    }

    public class Api
    {
        public void SomeApi(IActual actual)
        {
            actual.DoWork();
        }
    }

    public interface IInHand
    {
        void DoWorkDifferently();
    }

    public class InHand : IInHand
    {
        public void DoWorkDifferently()
        {
            Console.WriteLine("doing work slightly different ");
        }
    }

    public class ActualAdapterForInHand : IActual
    {
        IInHand hand = null;

        public ActualAdapterForInHand()
        {
            hand = new InHand();
        }

        public ActualAdapterForInHand(IInHand hnd)
        {
            hand = hnd;
        }

        public void DoWork()
        {
            hand.DoWorkDifferently();
        }
    }

    /*Decorator*/

    public interface IReady
    {
        void GetReady();
    }

    public class Male : IReady
    {
        public void GetReady()
        {
            Console.WriteLine("Taking bath.. ");
            Console.WriteLine("Dress up....");
        }
    }

    public class Female : IReady
    {
        public void GetReady()
        {
            Console.WriteLine("Taking bath.. ");
            Console.WriteLine("Dress up....");
            Console.WriteLine("Make up....");
        }
    }

    //this is a decorator
    public class Beautician : IReady
    {
        IReady ready = null;

        public Beautician(IReady rdy)
        {
            ready = rdy;
        }

        public void GetReady()
        {
            ready.GetReady();
            Console.WriteLine("Style hair ");

            if (ready is Female)
            {
                for (int i = 1; i <= 10; i++)
                {
                    Console.WriteLine("doing ready process " + i);
                }

            }
        }
    }

}

-3

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

ดังนั้นจึงมุ่งเน้นที่หลักการที่เป็นของแข็งมากขึ้นหลักการเขียนโค้ดที่สะอาดและ ttd


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