อะไรคือเหตุผลในการสร้างวิธีการบางอย่างสำหรับชนิดข้อมูลคงที่?
ตัวอย่างเช่นใน C # มีวิธีการแบบคงที่ในการบอกว่าสตริงเป็นโมฆะหรือว่างเปล่าค้นหาองค์ประกอบในอาร์เรย์การล้างอาร์เรย์เป็นต้นอย่างไรก็ตามมีวิธีอินสแตนซ์สำหรับการแทนที่อักขระในสตริงและทั้งแบบคงที่และอินสแตนซ์ วิธีการคัดลอกองค์ประกอบระหว่างอาร์เรย์
ในทำนองเดียวกันใน Python มีฟังก์ชั่นสำหรับการรับความยาวของรายการเพื่อกรองรายการ ฯลฯ แต่วิธีการเช่นในการค้นหาดัชนีขององค์ประกอบและสำหรับการคัดลอกรายการ
ในทางตรงกันข้ามใน JavaScript การดำเนินการใด ๆ ที่ฉันต้องทำในประเภทข้อมูลในตัวจะสามารถเข้าถึงได้ด้วยวิธีการอินสแตนซ์หรือคุณสมบัติ
แล้วอะไรคือเหตุผลในการทำให้บางสิ่งคงที่และอื่น ๆ ไม่ได้?
แก้ไข : เพื่อความชัดเจนฉันเข้าใจจุดประสงค์ของวิธีการคงที่ คำถามของฉันมีมากขึ้นเกี่ยวกับสาเหตุที่วิธีการบางอย่างถูกเขียนเป็นแบบคงที่เมื่อสามารถเขียนเป็นวิธีอินสแตนซ์ได้ เช่นเดียวกับFind
อาร์เรย์และFormat
สตริงใน C # และfilter
และlen
ใน Python
คำตอบ
แก้ไข : คำถามได้รับการกลั่นกรองแล้วดังนั้นฉันจะปรับแต่งคำตอบของฉัน แต่ทิ้งคำถามก่อนหน้าไว้ด้านล่างเพื่อไม่ให้ความคิดเห็นที่ไม่เกี่ยวข้อง
อาจมีสาเหตุหลายประการในการนำเมธอดไปใช้เป็นวิธีการแบบคงที่แทนที่จะเป็นวิธีอินสแตนซ์ด้วยภาษาหรือเฟรมเวิร์กที่แตกต่างกันอาจมีเหตุผลต่างกัน
อินเทอร์เฟซสาธารณะของอ็อบเจ็กต์คือสัญญา หาก
Array
ประเภทของคุณแสดงSort
วิธีการทุกอาร์เรย์ต่อจากนี้ไม่ว่าจะเป็นภาษาประเภทใดหรือเวอร์ชันใดจำเป็นต้องรองรับ อย่างไรก็ตามหาก anArray
เป็นเพียงการแสดงข้อมูลในหน่วยความจำด้วยสัญญาบาง ๆ และตรรกะถูกย้ายไปยังคลาสเช่นArray.Sort
นี้จะช่วยให้คุณมีความยืดหยุ่นมากขึ้นในการขยายหรือปรับเปลี่ยนพฤติกรรมของคุณในขณะที่ไม่ทำลายความเข้ากันได้ดูคำพูดนี้จากClean Codeของ Bob Martin :
วัตถุเปิดเผยพฤติกรรมและซ่อนข้อมูล โครงสร้างข้อมูลเปิดเผยข้อมูลและไม่มีพฤติกรรมสำคัญ "
ในกรณีนี้List
คลาสคือคลาสที่เปิดเผยพฤติกรรมซึ่งจะซ่อนข้อมูล (ใช้งานเป็นอาร์เรย์ที่ปรับขนาดได้ แต่เป็นรายละเอียดการนำไปใช้งาน) แต่จะแสดงฟังก์ชันการทำงาน int[]
แต่เป็นโครงสร้างข้อมูล เป็นint
บล็อกที่จัดสรรตามลำดับ มีLength
คุณสมบัติเนื่องจากเป็นส่วนหนึ่งของข้อมูลแต่ไม่มีพฤติกรรมมากนัก - พฤติกรรมจะถูกถ่ายไปยังคลาสที่ทำงานกับมัน
- มันอาจจะเป็นตัวเลือกโวหาร Python ไม่ใช่ภาษา OO เพียงอย่างเดียวและอาจไม่มีการรับประกัน Java / C # "ทุกอย่างเป็นอ็อบเจ็กต์" ดังนั้นจึงเลือกใช้ฟังก์ชันภาษา
len()
ที่สามารถใช้ได้ไม่ว่าพารามิเตอร์จะเป็นอินสแตนซ์อ็อบเจ็กต์หรือไม่ก็ตาม
คำตอบก่อนหน้า
เหตุผลที่อยู่เบื้องหลังวิธีการคงใน C # คือการมีวิธีการที่มีการเชื่อมโยงกับประเภทแต่ไม่ไปยังอินสแตนซ์ อาจมีสาเหตุหลายประการดังนี้
- วิธีการที่สามารถดำเนินการได้ทั้งในอินสแตนซ์และ
null
เช่นเดียวกับที่string.IsNullOrEmpty
เป็นธรรมชาติไม่สามารถเป็นวิธีการของอินสแตนซ์ได้เนื่องจากอาจไม่มีอินสแตนซ์ - เมธอดของโรงงานที่สร้างอินสแตนซ์ในทำนองเดียวกันไม่มีอินสแตนซ์ที่จะเรียกใช้ ยกตัวอย่างเช่นใครบางคนเลิกคงวิธีการส่งกลับตัวอย่างใหม่จากประเภทที่ได้มาจาก
WebRequest.Create()
WebRequest
- แม้ว่าจะลืมได้ง่าย แต่. NET มีการจัดการที่แตกต่างกันสำหรับประเภทอินทิกรัลดั้งเดิม (
int i =5
) และประเภทการอ้างอิงแบบกล่องรอบ ๆ (object boxed = 5
) หากคุณเรียกใช้เมธอดในประเภทค่า (int i = 5; t.ToString();
) คุณจะต้องเสียค่าใช้จ่ายในการชกมวย นั่นเป็นเหตุผลที่การดำเนินการบางอย่างไม่ได้กำหนดเป็นวิธีการบนวัตถุ แต่เป็นวิธีการแบบคงที่ที่ยอมรับค่า นั่นเป็นเหตุผลที่การดำเนินการทางคณิตศาสตร์เช่นMath.Abs
ไม่ได้กำหนดเป็นวิธีการในประเภทบรรจุกล่อง แต่เป็นฟังก์ชันคงที่ที่รับและส่งคืนค่า - บางครั้งวิธีการแบบคงที่จะใช้เพื่อ "กำหนดค่า" ประเภทไม่ใช่อินสแตนซ์ที่เฉพาะเจาะจง แต่เป็นการทำงานของประเภทนั้นในระบบ ตัวอย่างเช่น
[ServicePointManager.SetTcpKeepAlive()][1]
กำหนดค่าลักษณะการทำงานของคลาสทั้งหมดที่ใช้สแต็ก HTTP ที่แบ่งใช้ใน. NET ดังนั้นคุณสามารถกำหนดค่าได้ทั้งหมดโดยใช้วิธีการแบบคงที่เหล่านี้
วิธีการคงที่มีความหมายมาก
- เมื่อเมธอดเกี่ยวข้องกับประเภท แต่ไม่ต้องการอินสแตนซ์ที่มีอยู่ หรือ
- เมื่อภาษารองรับการกำหนดเนมสเปซผ่านคลาสเท่านั้น
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)
บนวัตถุชนิดใด ๆ ไม่เพียง แต่ในอาร์เรย์ ดังนั้นวิธีการอินสแตนซ์จะไม่ทำงานเว้นแต่จะเป็นส่วนหนึ่งของต้นแบบของทุกออบเจ็กต์