คำจำกัดความ: ห่อหุ้มการดำเนินการบางอย่างที่ดำเนินการกับแต่ละองค์ประกอบในโครงสร้างข้อมูลที่แน่นอน มันสามารถกำหนดการดำเนินการใหม่ที่ดำเนินการกับองค์ประกอบเหล่านี้โดยไม่ต้องเปลี่ยนโครงสร้างข้อมูล
ประเภท: รูปแบบพฤติกรรม
แผนภาพชั้นเรียน:
ตัวอย่าง:
ตัวอย่างเช่นคิดเกี่ยวกับการเพิ่มประเภทของสินค้าที่แตกต่างกันในรถเข็นและเมื่อคลิกที่เช็คเอาต์จะคำนวณค่าธรรมเนียมที่จะชำระสำหรับสินค้าที่แตกต่างกันทั้งหมด ตอนนี้ตรรกะการคำนวณคือการคำนวณราคาของสินค้าประเภทต่าง ๆ เหล่านี้ หรือกล่าวอีกนัยหนึ่งเราถ่ายโอนตรรกะนี้ไปยังคลาสอื่นผ่านโหมดผู้เยี่ยมชม มาใช้ตัวอย่างรูปแบบของผู้เยี่ยมชมนี้กันเถอะ
ในการใช้รูปแบบของผู้เข้าชมสิ่งแรกที่ต้องทำคือการสร้างคลาสที่สามารถเพิ่มลงในตะกร้าสินค้าเพื่อแสดงรายการประเภทต่าง ๆ (itemElements)
itemelement.javapackage com.journalev.design.visitor; อินเตอร์เฟสสาธารณะ imitelement {Public Int Accept (ShoppingCartVisitor ผู้เยี่ยมชม);}โปรดทราบว่าวิธีการยอมรับยอมรับผู้เข้าชมเป็นพารามิเตอร์ แน่นอนว่ามีวิธีอื่นในการระบุผลิตภัณฑ์โดยละเอียดที่นี่ แต่เพื่อความเรียบง่ายไม่จำเป็นต้องพิจารณารายละเอียดมากเกินไปที่นี่โดยมุ่งเน้นไปที่โหมดผู้เข้าชมเท่านั้น
ตอนนี้สร้างคลาสเอนทิตีสำหรับผลิตภัณฑ์ที่แตกต่างกัน
book.java
แพ็คเกจ com.journaldev.design.visitor; หนังสือชั้นเรียนสาธารณะใช้ itemelement {ราคา int ส่วนตัว; สตริงส่วนตัว isbnnumber; หนังสือสาธารณะ (ค่าใช้จ่าย int, string isbn) {this.price = ต้นทุน; this.isbnnumber = isbn; } public int getPrice () {ราคาคืน; } สตริงสาธารณะ getIsbnnumber () {return isbnnumber; } @Override Public Int Accept (ShoppingCartVisitor ผู้เยี่ยมชม) {return Visitor.Visit (นี่); -ผลไม้. java
แพ็คเกจ com.journaldev.design.visitor; ผลไม้ระดับสาธารณะดำเนินการ imitelement {private int priceperkg; น้ำหนัก int ส่วนตัว; ชื่อสตริงส่วนตัว; ผลไม้สาธารณะ (int pricekg, int wt, สตริง nm) {this.priceperkg = pricekg; this.weight = wt; this.name = nm; } สาธารณะ int getPricePerkg () {return priceperkg; } public int getweight () {น้ำหนักกลับ; } สตริงสาธารณะ getName () {return this.name; } @Override Public Int Accept (ShoppingCartVisitor ผู้เยี่ยมชม) {return Visitor.Visit (นี่); - โปรดทราบว่าการใช้วิธีการยอมรับ () อยู่ในคลาสเอนทิตีซึ่งเรียกวิธีการเยี่ยมชมของผู้เข้าชม () เพื่อส่งผ่านวัตถุคลาสปัจจุบันเป็นพารามิเตอร์ของตัวเอง
ที่นี่วิธีการเยี่ยมชม () ที่ใช้สำหรับสินค้าประเภทต่าง ๆ จะถูกนำไปใช้ในคลาสเอนทิตีของอินเทอร์เฟซผู้เข้าชม
Shoppingcartvisitor.java
แพ็คเกจ com.journaldev.design.visitor; อินเตอร์เฟสสาธารณะ ShoppingCartVisitor {int เยี่ยมชม (หนังสือเล่ม); การเยี่ยมชม int (ผลไม้ผลไม้);}ตอนนี้อินเทอร์เฟซของผู้เข้าชมจะถูกนำไปใช้และตรรกะของการคำนวณค่าใช้จ่ายของตัวเองสำหรับแต่ละผลิตภัณฑ์
ShoppingCartVisitorImpl.java
แพ็คเกจ com.journaldev.design.visitor; Public Class ShoppingCartVisitorImpl ใช้ photioncartvisitor {@Override การเยี่ยมชมสาธารณะสาธารณะ (หนังสือ) {int cost = 0; // ใช้ 5 $ ส่วนลดถ้าราคาหนังสือมากกว่า 50 ถ้า (book.getPrice ()> 50) {cost = book.getPrice ()-5; } ค่าใช้จ่ายอื่น = book.getPrice (); System.out.println ("หนังสือ isbn ::"+book.getisbnnumber ()+"cost ="+ราคา); ต้นทุนผลตอบแทน; } @Override การเยี่ยมชมสาธารณะสาธารณะ (ผลไม้) {int cost = fruit.getPricePerkg ()*fruit.getweight (); System.out.println (fruit.getName () + "cost =" + cost); ต้นทุนผลตอบแทน; -ทีนี้มาดูวิธีการใช้ในโปรแกรม
ShoppingCartClient.java
แพ็คเกจ com.journalev.design.visitor; Public Class Shoppingcartclient {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {itemelement [] รายการ = itemelement ใหม่ [] {หนังสือเล่มใหม่ (20, "1234"), หนังสือเล่มใหม่ (100, "5678"), ผลไม้ใหม่ (10, 2, "Banana") int total = calculatePrice (รายการ); System.out.println ("ค่าใช้จ่ายทั้งหมด ="+รวม); } private static int calculatePrice (itemElement [] รายการ) {ShoppingCartVisitor ผู้เยี่ยมชม = ใหม่ ShoppingCartVisitorImpl (); int sum = 0; สำหรับ (รายการ itemElement: รายการ) {sum = sum + item.accept (ผู้เยี่ยมชม); } return sum; -เมื่อเรียกใช้โปรแกรมข้างต้นเราจะได้รับผลลัพธ์ต่อไปนี้
หนังสือ isbn :: 1234 ค่าใช้จ่าย = 20book isbn :: 5678 ต้นทุน = 95banana ราคา = 20apple ราคา = 25total ต้นทุน = 160
โปรดทราบว่าการใช้งานที่นี่ดูเหมือนจะเหมือนกับวิธีการยอมรับ () สำหรับผลิตภัณฑ์ทั้งหมด แต่ก็อาจแตกต่างกัน ตัวอย่างเช่นหากผลิตภัณฑ์ว่างเปล่าสามารถทำการตรวจสอบเชิงตรรกะและไม่เรียกวิธีการเยี่ยมชม () อีกต่อไป
ข้อดีของโหมดผู้เยี่ยมชม:
ปฏิบัติตามหลักการของความรับผิดชอบเดี่ยว: ในสถานการณ์ใด ๆ ที่โหมดผู้เข้าชมใช้งานได้การดำเนินการที่ต้องห่อหุ้มในผู้เข้าชมในคลาสองค์ประกอบจะต้องดำเนินการที่มีส่วนเกี่ยวข้องกับคลาสองค์ประกอบเพียงเล็กน้อยและมีความผันผวน ในอีกด้านหนึ่งการใช้โหมดผู้เยี่ยมชมเป็นไปตามหลักการของความรับผิดชอบเดี่ยวและในทางกลับกันเนื่องจากการดำเนินการที่ห่อหุ้มอยู่มักจะผันผวนเมื่อมีการเปลี่ยนแปลงเกิดขึ้นการขยายตัวของส่วนที่เปลี่ยนแปลงสามารถทำได้โดยไม่ต้องเปลี่ยนคลาสองค์ประกอบเอง
ความสามารถในการปรับขนาดที่ดี: คลาสองค์ประกอบสามารถขยายการดำเนินงานที่แตกต่างกันโดยยอมรับผู้เข้าชมที่แตกต่างกัน
สถานการณ์ที่เกี่ยวข้องสำหรับโหมดผู้เข้าชม:
หากมีการดำเนินการบางอย่างในวัตถุที่ไม่เกี่ยวข้องกับวัตถุ (หรือที่เกี่ยวข้องอย่างอ่อนแอ) และเพื่อหลีกเลี่ยงการดำเนินการเหล่านี้ที่ปนเปื้อนวัตถุคุณสามารถใช้โหมดผู้เข้าชมเพื่อห่อหุ้มการดำเนินการเหล่านี้ลงในผู้เข้าชม
หากมีการดำเนินการที่คล้ายกันในกลุ่มวัตถุเพื่อหลีกเลี่ยงรหัสซ้ำจำนวนมากการดำเนินการซ้ำเหล่านี้ยังสามารถห่อหุ้มเข้าไปในผู้เข้าชมได้
อย่างไรก็ตามโหมดผู้เยี่ยมชมไม่สมบูรณ์แบบและยังมีข้อบกพร่องร้ายแรง: การเพิ่มคลาสองค์ประกอบใหม่นั้นยากกว่า ผ่านรหัสของรูปแบบผู้เข้าชมเราจะเห็นได้ว่าในคลาสผู้เข้าชมแต่ละคลาสองค์ประกอบมีวิธีการประมวลผลที่สอดคล้องกัน กล่าวคือแต่ละคลาสองค์ประกอบจะต้องถูกเพิ่มเพื่อปรับเปลี่ยนคลาสผู้เข้าชม (รวมถึงคลาสย่อยหรือคลาสการใช้งานของคลาสผู้เยี่ยมชม) ซึ่งค่อนข้างลำบากในการแก้ไข กล่าวคือเมื่อจำนวนคลาสองค์ประกอบไม่แน่นอนโหมดผู้เข้าชมควรใช้ด้วยความระมัดระวัง ดังนั้นโหมดผู้เยี่ยมชมจึงเหมาะสำหรับการปรับแต่งฟังก์ชั่นที่มีอยู่ใหม่ ตัวอย่างเช่นหากมีการกำหนดฟังก์ชั่นพื้นฐานของโครงการข้อมูลของคลาสองค์ประกอบจะถูกกำหนดโดยทั่วไปและจะไม่เปลี่ยนแปลง สิ่งที่จะเปลี่ยนแปลงคือการดำเนินการที่เกี่ยวข้องภายในองค์ประกอบเหล่านี้ ในเวลานี้เราสามารถใช้โหมดผู้เยี่ยมชมเพื่อ refactor รหัสต้นฉบับเพื่อให้สามารถแก้ไขฟังก์ชั่นดั้งเดิมได้โดยไม่ต้องแก้ไขแต่ละคลาสองค์ประกอบ
สรุป:
ในฐานะ GOF ผู้เขียนรูปแบบการออกแบบอธิบายโหมดผู้เยี่ยมชม: ในกรณีส่วนใหญ่คุณต้องใช้โหมดผู้เยี่ยมชม แต่เมื่อคุณต้องการคุณต้องการมันจริงๆ แน่นอนว่านี่เป็นเพียงสำหรับผู้ชายที่ยิ่งใหญ่ที่แท้จริง ในความเป็นจริง (อย่างน้อยในสภาพแวดล้อมที่ฉันอยู่) หลายคนมักจะติดกับรูปแบบการออกแบบ เมื่อใช้รูปแบบการออกแบบพวกเขาไม่เคยพิจารณาอย่างจริงจังว่ารูปแบบที่พวกเขาใช้นั้นเหมาะสำหรับสถานการณ์นี้หรือไม่ แต่มักจะต้องการแสดงความสามารถในการควบคุมการออกแบบเชิงวัตถุ หากคุณมีความคิดนี้เมื่อเขียนโปรแกรมคุณมักจะใช้รูปแบบการออกแบบที่ใช้ในทางที่ผิด ดังนั้นเมื่อเรียนรู้รูปแบบการออกแบบคุณต้องเข้าใจการบังคับใช้ของรูปแบบ จำเป็นต้องใช้รูปแบบเพราะคุณเข้าใจข้อดีของมันไม่ต้องใช้รูปแบบเพราะคุณเข้าใจข้อเสียของมัน แทนที่จะใช้รูปแบบเพราะคุณไม่เข้าใจข้อเสียของมันไม่ใช้รูปแบบเพราะคุณไม่เข้าใจข้อดีของมัน