อะไรคือเหตุผลในการสร้างวิธีการบางอย่างสำหรับชนิดข้อมูลคงที่?

Aug 15 2020

ตัวอย่างเช่นใน C # มีวิธีการแบบคงที่ในการบอกว่าสตริงเป็นโมฆะหรือว่างเปล่าค้นหาองค์ประกอบในอาร์เรย์การล้างอาร์เรย์เป็นต้นอย่างไรก็ตามมีวิธีอินสแตนซ์สำหรับการแทนที่อักขระในสตริงและทั้งแบบคงที่และอินสแตนซ์ วิธีการคัดลอกองค์ประกอบระหว่างอาร์เรย์

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

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

แล้วอะไรคือเหตุผลในการทำให้บางสิ่งคงที่และอื่น ๆ ไม่ได้?

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

คำตอบ

2 AvnerShahar-Kashtan Aug 15 2020 at 15:09

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

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

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

  2. ดูคำพูดนี้จากClean Codeของ Bob Martin :

วัตถุเปิดเผยพฤติกรรมและซ่อนข้อมูล โครงสร้างข้อมูลเปิดเผยข้อมูลและไม่มีพฤติกรรมสำคัญ "

ในกรณีนี้Listคลาสคือคลาสที่เปิดเผยพฤติกรรมซึ่งจะซ่อนข้อมูล (ใช้งานเป็นอาร์เรย์ที่ปรับขนาดได้ แต่เป็นรายละเอียดการนำไปใช้งาน) แต่จะแสดงฟังก์ชันการทำงาน int[]แต่เป็นโครงสร้างข้อมูล เป็นintบล็อกที่จัดสรรตามลำดับ มีLengthคุณสมบัติเนื่องจากเป็นส่วนหนึ่งของข้อมูลแต่ไม่มีพฤติกรรมมากนัก - พฤติกรรมจะถูกถ่ายไปยังคลาสที่ทำงานกับมัน

  1. มันอาจจะเป็นตัวเลือกโวหาร Python ไม่ใช่ภาษา OO เพียงอย่างเดียวและอาจไม่มีการรับประกัน Java / C # "ทุกอย่างเป็นอ็อบเจ็กต์" ดังนั้นจึงเลือกใช้ฟังก์ชันภาษาlen()ที่สามารถใช้ได้ไม่ว่าพารามิเตอร์จะเป็นอินสแตนซ์อ็อบเจ็กต์หรือไม่ก็ตาม

คำตอบก่อนหน้า

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

  1. วิธีการที่สามารถดำเนินการได้ทั้งในอินสแตนซ์และnullเช่นเดียวกับที่string.IsNullOrEmptyเป็นธรรมชาติไม่สามารถเป็นวิธีการของอินสแตนซ์ได้เนื่องจากอาจไม่มีอินสแตนซ์
  2. เมธอดของโรงงานที่สร้างอินสแตนซ์ในทำนองเดียวกันไม่มีอินสแตนซ์ที่จะเรียกใช้ ยกตัวอย่างเช่นใครบางคนเลิกคงวิธีการส่งกลับตัวอย่างใหม่จากประเภทที่ได้มาจากWebRequest.Create()WebRequest
  3. แม้ว่าจะลืมได้ง่าย แต่. NET มีการจัดการที่แตกต่างกันสำหรับประเภทอินทิกรัลดั้งเดิม ( int i =5) และประเภทการอ้างอิงแบบกล่องรอบ ๆ ( object boxed = 5) หากคุณเรียกใช้เมธอดในประเภทค่า ( int i = 5; t.ToString();) คุณจะต้องเสียค่าใช้จ่ายในการชกมวย นั่นเป็นเหตุผลที่การดำเนินการบางอย่างไม่ได้กำหนดเป็นวิธีการบนวัตถุ แต่เป็นวิธีการแบบคงที่ที่ยอมรับค่า นั่นเป็นเหตุผลที่การดำเนินการทางคณิตศาสตร์เช่นMath.Absไม่ได้กำหนดเป็นวิธีการในประเภทบรรจุกล่อง แต่เป็นฟังก์ชันคงที่ที่รับและส่งคืนค่า
  4. บางครั้งวิธีการแบบคงที่จะใช้เพื่อ "กำหนดค่า" ประเภทไม่ใช่อินสแตนซ์ที่เฉพาะเจาะจง แต่เป็นการทำงานของประเภทนั้นในระบบ ตัวอย่างเช่น[ServicePointManager.SetTcpKeepAlive()][1]กำหนดค่าลักษณะการทำงานของคลาสทั้งหมดที่ใช้สแต็ก HTTP ที่แบ่งใช้ใน. NET ดังนั้นคุณสามารถกำหนดค่าได้ทั้งหมดโดยใช้วิธีการแบบคงที่เหล่านี้
5 amon Aug 15 2020 at 15:28

วิธีการคงที่มีความหมายมาก

  • เมื่อเมธอดเกี่ยวข้องกับประเภท แต่ไม่ต้องการอินสแตนซ์ที่มีอยู่ หรือ
  • เมื่อภาษารองรับการกำหนดเนมสเปซผ่านคลาสเท่านั้น

C # รองรับฟังก์ชันในฐานะสมาชิกของคลาสเท่านั้นดังนั้นฟังก์ชันตัวช่วยควรเขียนเป็นวิธีการแบบคงที่ MathคลาสC # เป็นตัวอย่างที่สำคัญ

JavaScript ไม่มีคลาส แต่ตัวแปรที่ไม่ใช่โลคัลทุกตัวเชื่อมโยงกับอ็อบเจ็กต์บางตัว - ในเบราว์เซอร์ API ส่วนใหญ่สามารถเข้าถึงได้ผ่านwindowอ็อบเจ็กต์ Array.isArray(x)แต่มีวิธีการที่สามารถเข้าถึงได้ผ่านชั้นเหมือนวัตถุเช่น

Python มีการออกแบบที่แปลกประหลาดซึ่งส่วนใหญ่เป็นเชิงวัตถุ แต่มีฟังก์ชันในตัวบางอย่างเช่นlen()หรือiter()ส่วนใหญ่เป็นเพราะเหตุผลทางประวัติศาสตร์ ภายใต้ประทุนพวกเขาเรียกใช้วิธีการจริงเช่นiter(x)โดยปกติจะx.__iter__()มีทางเลือกสำหรับวัตถุที่สามารถจัดทำดัชนีได้เช่นรายการ

วิธีที่น่าสนใจกว่าคือวิธีการที่staticไม่ได้เป็นเพราะนิสัยใจคอของภาษา แต่เป็นเพราะมันสมเหตุสมผล วิธีการแบบคอนสตรัคเตอร์หรือแบบโรงงานเป็นตัวอย่างคลาสสิกที่เราไม่มีอ็อบเจ็กต์ที่เราสามารถเรียกใช้เมธอดได้ ฟังก์ชั่นบางอย่างไม่ทำงานบนวัตถุชิ้นเดียวเช่นString.IsNullOrEmpty(x)ทำงานบนวัตถุศูนย์หรือวัตถุเดียว วิธีนี้ใช้ไม่ได้เช่นx.IsNullOrEmpty()จะทำให้เกิดข้อยกเว้นหากเป็นโมฆะ! Array.isArray(x)วิธีการใน JS เป็นอีกหนึ่งตัวอย่างที่ดี: เราต้องการที่จะเรียกisArray(x)บนวัตถุชนิดใด ๆ ไม่เพียง แต่ในอาร์เรย์ ดังนั้นวิธีการอินสแตนซ์จะไม่ทำงานเว้นแต่จะเป็นส่วนหนึ่งของต้นแบบของทุกออบเจ็กต์