ใช้รูปแบบกลยุทธ์และรูปแบบคำสั่ง


121

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

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

การกำหนดอะไรเป็นแนวทางว่าจะใช้รูปแบบเดียวหรืออีกแบบ

คำตอบ:


94

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

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

ตารางลำดับชั้นการห่อหุ้มรูปแบบการออกแบบ

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

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

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


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

4
@KTF เลขที่ รูปแบบคำสั่งใช้อ็อบเจ็กต์ซึ่งมีข้อมูลที่จำเป็น (เช่นตัวรับตัวเลือกอาร์กิวเมนต์) เพื่อเรียกใช้เมธอดของอ็อบเจ็กต์ เป็นรูปแบบที่เรียบง่ายซึ่งสามารถใช้ในรูปแบบการออกแบบอื่น ๆ เช่น Chain of Responsibility, Collection และรูปแบบไปป์ไลน์ที่คุณอธิบาย "สัญญาประเภทต่างๆ" ที่มอบให้โดยผู้แทนของคุณเป็นอีกรูปแบบหนึ่งคืออินเทอร์เฟซ
Huperniketes

50

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

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


นั่นทำให้รู้สึกว่าen.wikipedia.org/wiki/Command_Patternไคลเอนต์และผู้เรียกใช้ถูกผูกติดกัน แต่ในเวลาเดียวกันพวกเขาไม่รู้เกี่ยวกัน!
Kalpesh Soni

26

ตอบคำถามเก่ามาก (มีใครเห็นคำตอบล่าสุดแทนที่จะเป็นคนที่โหวตมากที่สุด?)

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

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

ในกรณีของกลยุทธ์สิ่งที่แตกต่างกันไปเป็นอัลกอริทึม ตัวอย่างเช่นออบเจ็กต์กลยุทธ์หนึ่งรู้วิธีการส่งออกไปยังไฟล์ XML ในขณะที่อีกผลลัพธ์หนึ่งเป็น JSON อัลกอริทึมที่แตกต่างกันจะถูกเก็บไว้ ( ห่อหุ้ม ) ในคลาสต่างๆ มันเป็นเรื่องง่ายเหมือนที่.

ในกรณีของคำสั่งสิ่งที่แตกต่างกันไปคือคำขอนั้นเอง คำขออาจมาจากFile Menu > DeleteหรือหรือRight Click > Context Menu > Delete Just Delete Button pressedทั้งสามกรณีสามารถสร้างอ็อบเจ็กต์คำสั่งประเภทเดียวกัน 3 ชิ้น อ็อบเจ็กต์คำสั่งเหล่านี้แสดงถึงคำขอลบ 3 รายการเท่านั้น ไม่ใช่อัลกอริทึมการลบ เนื่องจากคำขอเป็นวัตถุจำนวนมากในตอนนี้เราจึงสามารถจัดการได้อย่างง่ายดาย ทันใดนั้นมันก็กลายเป็นเรื่องไม่สำคัญที่จะมอบฟังก์ชันต่างๆเช่นเลิกทำหรือทำซ้ำ

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

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

ฉันคิดว่า Command ช่วยให้เราทำความเข้าใจเกี่ยวกับการห่อหุ้มได้กว้างขึ้นในขณะที่ Strategy ให้การใช้การห่อหุ้มและความหลากหลายตามธรรมชาติ


15

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

อาจจะลองใช้ StrategyOne ก่อนหากผลลัพธ์ยังไม่ดีพอให้ลองใช้ StrategyTwo ...

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

เครื่องหมาย


2
RE: "หลายวิธีในการทำสิ่งเดียวกัน" - ดูเหมือนจะขัดแย้งกับตัวอย่างทั่วไปของกลยุทธ์ โดยเฉพาะอย่างยิ่งคลาสที่มีคลาสการใช้งานที่ทำบวกลบคูณและอื่น ๆ อาจจะไม่ใช่ตัวอย่างที่ดี?
Joshua Davis

1
@JoshuaDavis ทั้งหมดเหล่านี้ "substratagies" เป็นกรณีพิเศษของกลยุทธ์ที่หนึ่ง: การดำเนินงานเกี่ยวกับคณิตศาสตร์ พวกเขามีอาร์กิวเมนต์ทั่วไป (2 ตัวถูกดำเนินการ) และสร้างค่าหนึ่งเป็นผลลัพธ์ การทำแบบเดียวกัน (เป็นแบล็กบ็อกซ์) เป็นสิ่งที่แตกต่างกันไปขึ้นอยู่กับการนำไปใช้งาน ดังนั้นฉันจึงไม่เห็นความขัดแย้งที่นี่ แต่ค่อนข้างตรงกันข้าม: ตัวอย่างที่ดี =)
jungle_mole

7

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

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

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

กลยุทธ์เป็นบิตที่แตกต่าง: มันเป็นผูกพันมากขึ้นในบางพื้นที่ กลยุทธ์อาจกำหนดกฎเพื่อจัดรูปแบบวันที่ (ใน UTC? locale เฉพาะ?) (กลยุทธ์ "จัดรูปแบบวันที่") หรือคำนวณกำลังสองสำหรับรูปเรขาคณิต (กลยุทธ์ "เครื่องคำนวณกำลังสอง") กลยุทธ์ในแง่นี้คือวัตถุฟลายเวทที่ใช้ข้อมูลเป็นข้อมูล ("วันที่", "รูป", ... ) และตัดสินใจบนพื้นฐานของมัน บางทีอาจไม่ใช่สิ่งที่ดีที่สุด แต่เป็นตัวอย่างที่ดีของกลยุทธ์หนึ่งที่เชื่อมต่อกับjavax.xml.transform.Sourceอินเทอร์เฟซ: ขึ้นอยู่กับว่าวัตถุที่ส่งผ่านนั้นDOMSourceหรือSAXSourceหรือStreamSourceกลยุทธ์ (= หม้อแปลง XSLT ในกรณีนี้) จะใช้กฎที่แตกต่างกันในการประมวลผล การดำเนินการอาจจะง่ายswitchหรือเกี่ยวข้องกับห่วงโซ่ของรูปแบบความรับผิดชอบ

แต่มีบางอย่างที่เหมือนกันระหว่างรูปแบบทั้งสองนี้: คำสั่งและกลยุทธ์ห่อหุ้มอัลกอริทึมภายในพื้นที่ความหมายเดียวกัน


1
ฉันถือว่าคำสั่งเป็นฟังก์ชันเรียกกลับหรือปฏิกิริยา ควรมีผู้เล่นอย่างน้อยสองคน: ผู้ร้องขอการดำเนินการและผู้ที่ดำเนินการ ... - ฉันเข้าใจสิ่งที่คุณพยายามจะพูด แต่ฉันอายที่จะใช้คำว่า 'เรียกกลับ' เพราะมักจะเป็นคำว่า 'โทรกลับ' หมายถึงการเรียกใช้แบบอะซิงโครนัสและคุณไม่จำเป็นต้องทำการเรียกใช้แบบอะซิงโครนัสเพื่อให้รูปแบบคำสั่งมีประโยชน์ ตรงประเด็น: Microsoft Word การคลิกปุ่มแถบเครื่องมือและการกดปุ่มทางลัดไม่เรียกใช้คำสั่งแบบอะซิงโครนัส แต่เราสามารถชื่นชมวิธีการใช้รูปแบบคำสั่งที่มีประโยชน์ในกรณีนี้
Jim G.

ฉันยอมรับแม้ว่าตามที่จิมบอกว่าฉันจะแก้ไขเพื่อลบการอ้างอิงถึงการโทรกลับ
JARC

ขอบคุณฉันได้สร้างส่วนขยายบางอย่างแล้ว แจ้งให้เราทราบหากคุณเห็นด้วย / ไม่เห็นด้วย
dma_k

5

คำสั่ง:

ส่วนประกอบพื้นฐาน:

  1. คำสั่งประกาศอินเทอร์เฟซสำหรับคำสั่งนามธรรมเช่นexecute()
  2. ผู้รับรู้วิธีดำเนินการคำสั่งเฉพาะ
  3. Invokerถือ ConcreteCommandซึ่งจะต้องดำเนินการ
  4. ลูกค้าสร้าง ConcreteCommandและกำหนดผู้รับ
  5. ConcreteCommandกำหนดการผูกมัดระหว่าง Commandและ Receiver

ขั้นตอนการทำงาน:

ลูกค้าเรียกInvoker => InvokerเรียกConcreteCommand => ConcreteCommandเรียกวิธีการรับซึ่งใช้วิธีการคำสั่งนามธรรม

ข้อได้เปรียบ : ไคลเอนต์ไม่ได้รับผลกระทบต่อการเปลี่ยนแปลงใน Command and Receiver Invoker ให้การมีเพศสัมพันธ์แบบหลวม ๆ ระหว่างไคลเอนต์และผู้รับ คุณสามารถเรียกใช้หลายคำสั่งด้วย Invoker เดียวกัน

คำสั่งรูปแบบที่ช่วยให้คุณสามารถดำเนินการคำสั่งเกี่ยวกับการที่แตกต่างกันรับโดยใช้แบบเดียวกันInvoker Invoker ไม่ทราบประเภทของผู้รับ

เพื่อความเข้าใจแนวคิดที่ดีขึ้นโปรดดูบทความ JournalDev โดยPankaj Kumarและบทความ dzone โดยJames Sugrueนอกเหนือจากลิงก์ Wikipedia

คุณสามารถใช้รูปแบบคำสั่งเพื่อ

  1. แยกตัวเรียกใช้และผู้รับคำสั่ง

  2. ใช้กลไกการโทรกลับ

  3. ใช้ฟังก์ชันการเลิกทำและทำซ้ำ

  4. รักษาประวัติของคำสั่ง

java.lang.Threadเป็นการใช้รูปแบบคำสั่งที่ดีวิธีหนึ่ง คุณสามารถรักษากระทู้เป็นทรงและระดับการดำเนินRunnableเป็นConcreteCommonad / ตัวรับและrun()วิธีการตามที่สั่ง

สามารถอ่านรูปแบบคำสั่งเวอร์ชันเลิกทำ / ทำซ้ำได้ที่บทความของ Theodore Norvell

กลยุทธ์:

รูปแบบกลยุทธ์นั้นเข้าใจง่ายมาก ใช้รูปแบบนี้เมื่อ

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

ยกตัวอย่างองค์ประกอบค่าโดยสารของระบบการจองตั๋วเครื่องบิน

สายการบินต้องการเสนอค่าโดยสารที่แตกต่างกันในช่วงเวลาที่แตกต่างกัน - เดือน Peak และ Off Peak ในช่วงวันที่มีการเดินทางท่องเที่ยวเป็นจำนวนมากจึงต้องการกระตุ้นความต้องการโดยเสนอส่วนลดที่น่าสนใจ

ประเด็นสำคัญของรูปแบบกลยุทธ์ :

  1. มันเป็นรูปแบบพฤติกรรม
  2. ขึ้นอยู่กับการมอบหมาย
  3. มันเปลี่ยนความกล้าของวัตถุโดยการปรับเปลี่ยนพฤติกรรมวิธีการ
  4. ใช้เพื่อสลับระหว่างกลุ่มอัลกอริทึม
  5. มันเปลี่ยนพฤติกรรมของวัตถุในขณะทำงาน

บทความที่เกี่ยวข้องพร้อมตัวอย่างโค้ด:

ใช้รูปแบบการออกแบบคำสั่ง

ตัวอย่างรูปแบบกลยุทธ์ในโลกแห่งความจริง


0

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

  • สำหรับกลยุทธ์ส่วนประกอบที่ใช้อ็อบเจกต์จะรู้ว่าอ็อบเจ็กต์ทำอะไร (และจะใช้มันเพื่อทำงานส่วนหนึ่งของมันเอง) แต่มันไม่สนใจว่ามันจะทำงานอย่างไร

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

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

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