ใน Python ฉันควรใช้ฟังก์ชันแทนเมธอดเมื่อใด


118

Zen of Python ระบุว่าควรมีเพียงวิธีเดียวในการทำสิ่งต่างๆ แต่บ่อยครั้งที่ฉันประสบปัญหาในการตัดสินใจว่าจะใช้ฟังก์ชันเมื่อใดเทียบกับเมื่อใดควรใช้วิธีการ

ลองดูตัวอย่างเล็กน้อย - วัตถุ ChessBoard สมมติว่าเราต้องการวิธีการบางอย่างเพื่อให้ได้การเคลื่อนไหวของกษัตริย์ตามกฎหมายทั้งหมดที่มีอยู่บนกระดาน เราเขียน ChessBoard.get_king_moves () หรือ get_king_moves (chess_board)?

นี่คือคำถามที่เกี่ยวข้องบางส่วนที่ฉันดู:

คำตอบที่ฉันได้รับส่วนใหญ่สรุปไม่ได้:

เหตุใด Python จึงใช้เมธอดสำหรับฟังก์ชันบางอย่าง (เช่น list.index ()) แต่ฟังก์ชันอื่น ๆ (เช่น len (รายการ))

เหตุผลสำคัญคือประวัติศาสตร์ ฟังก์ชั่นถูกใช้สำหรับการดำเนินการที่เป็นแบบทั่วไปสำหรับกลุ่มของประเภทและมีจุดมุ่งหมายเพื่อใช้งานได้แม้กระทั่งกับอ็อบเจ็กต์ที่ไม่มีเมธอดเลย (เช่นทูเปิล) นอกจากนี้ยังสะดวกที่จะมีฟังก์ชันที่สามารถนำไปใช้กับคอลเลกชันอสัณฐานได้อย่างง่ายดายเมื่อคุณใช้คุณสมบัติการทำงานของ Python (map (), apply () et al)

ในความเป็นจริงการนำ len (), max (), min () มาใช้เป็นฟังก์ชันในตัวนั้นมีโค้ดน้อยกว่าการนำไปใช้เป็นวิธีการสำหรับแต่ละประเภท เราสามารถเล่นลิ้นเกี่ยวกับแต่ละกรณีได้ แต่เป็นส่วนหนึ่งของ Python และมันสายเกินไปที่จะทำการเปลี่ยนแปลงพื้นฐานดังกล่าวในตอนนี้ ฟังก์ชันจะต้องยังคงอยู่เพื่อหลีกเลี่ยงการแตกโค้ดจำนวนมาก

ในขณะที่น่าสนใจข้างต้นไม่ได้บอกมากนักว่าควรใช้กลยุทธ์ใด

นี่เป็นหนึ่งในเหตุผล - ด้วยวิธีการที่กำหนดเองนักพัฒนาจะมีอิสระที่จะเลือกชื่อเมธอดอื่นเช่น getLength (), length (), getlength () หรืออะไรก็ตาม Python บังคับใช้การตั้งชื่อที่เข้มงวดเพื่อให้สามารถใช้ฟังก์ชันทั่วไป len () ได้

น่าสนใจกว่าเล็กน้อย สิ่งที่ฉันใช้คือฟังก์ชั่นในแง่หนึ่งคืออินเทอร์เฟซเวอร์ชัน Pythonic

สุดท้ายจาก Guido เอง :

การพูดถึงความสามารถ / อินเทอร์เฟซทำให้ฉันนึกถึงชื่อเมธอดพิเศษที่ "โกง" ของเรา ในการอ้างอิงภาษากล่าวว่า "คลาสสามารถใช้การดำเนินการบางอย่างที่เรียกใช้โดยไวยากรณ์พิเศษ (เช่นการดำเนินการทางคณิตศาสตร์หรือการห้อยและการแบ่งส่วน) โดยกำหนดวิธีการที่มีชื่อพิเศษ" แต่มีวิธีการเหล่านี้ทั้งหมดที่มีชื่อพิเศษเช่น__len__หรือ__unicode__ซึ่งดูเหมือนจะถูกจัดเตรียมไว้เพื่อประโยชน์ของฟังก์ชันในตัวแทนที่จะสนับสนุนไวยากรณ์ สันนิษฐานว่าใน Python ที่ใช้อินเทอร์เฟซวิธีการเหล่านี้จะกลายเป็นเมธอดที่มีชื่อประจำบน ABC ดังนั้นจึง __len__กลายเป็น

class container:
  ...
  def len(self):
    raise NotImplemented

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

ฮึ่ม ฉันไม่แน่ใจว่าฉันเห็นด้วย (คิดว่า :-)

มีสองบิตของ "Python rationale" ที่ฉันอยากจะอธิบายก่อน

ก่อนอื่นฉันเลือก len (x) มากกว่า x.len () ด้วยเหตุผล HCI (ตามdef __len__()มาทีหลัง) มีสองสาเหตุที่เกี่ยวพันกันจริงๆทั้ง HCI:

(a) สำหรับการดำเนินการบางอย่างสัญกรณ์นำหน้าจะอ่านได้ดีกว่า postfix - การดำเนินการคำนำหน้า (และ infix!) มีประเพณีอันยาวนานในคณิตศาสตร์ซึ่งชอบสัญกรณ์ที่ภาพช่วยให้นักคณิตศาสตร์คิดเกี่ยวกับปัญหาได้ เปรียบเทียบง่ายที่เราเขียนสูตรเหมือนx*(a+b)เข้าไปx*a + x*bเพื่อความซุ่มซ่ามของการทำสิ่งเดียวกันโดยใช้สัญกรณ์ OO ดิบ

(b) เมื่อฉันอ่านรหัสที่ระบุว่าlen(x)ฉันรู้ว่ากำลังขอความยาวของบางสิ่ง สิ่งนี้บอกฉันสองสิ่ง: ผลลัพธ์คือจำนวนเต็มและอาร์กิวเมนต์คือคอนเทนเนอร์บางประเภท ไปในทางตรงกันข้ามเมื่อฉันอ่านx.len()ฉันต้องรู้อยู่แล้วว่าเป็นชนิดของภาชนะที่ใช้อินเตอร์เฟซหรือการสืบทอดจากคลาสที่มีมาตรฐานบางอย่างx len()เป็นสักขีพยานในความสับสนที่เราพบในบางครั้งเมื่อชั้นเรียนที่ไม่ได้ใช้การทำแผนที่มี a get()หรือkeys() method หรือสิ่งที่ไม่ใช่ไฟล์มีwrite()วิธีการ

พูดในทำนองเดียวกันว่าฉันเห็นว่า 'len' เป็นการทำงานใน ตัว ฉันเกลียดที่จะสูญเสียสิ่งนั้นไป ฉันไม่สามารถพูดได้อย่างแน่นอนว่าคุณหมายถึงอย่างนั้นหรือไม่ แต่ 'def len (self): ... ' ดูเหมือนว่าคุณต้องการลดระดับเป็นวิธีการธรรมดา ฉันเป็นอย่างยิ่ง -1 สำหรับสิ่งนั้น

บิตที่สองของงูหลามเหตุผลฉันสัญญาว่าจะอธิบายคือเหตุผลว่าทำไมผมเลือกวิธีการพิเศษที่จะมองและไม่เพียง__special__ specialฉันคาดว่าจะมีการดำเนินการจำนวนมากที่คลาสอาจต้องการแทนที่มาตรฐานบางอย่าง (เช่น__add__หรือ__getitem__) บางอย่างไม่เป็นมาตรฐาน (เช่นของดอง__reduce__เป็นเวลานานไม่มีการรองรับรหัส C เลย) ฉันไม่ต้องการให้หน่วยปฏิบัติการพิเศษเหล่านี้ใช้ชื่อเมธอดธรรมดาเพราะจากนั้นคลาสที่มีอยู่แล้วหรือคลาสที่เขียนโดยผู้ใช้โดยไม่มีหน่วยความจำสารานุกรมสำหรับวิธีการพิเศษทั้งหมดจะต้องรับผิดชอบต่อการกำหนดการดำเนินการโดยไม่ได้ตั้งใจซึ่งไม่ได้ตั้งใจจะใช้ ซึ่งอาจส่งผลร้ายตามมา Ivan Krstićอธิบายสิ่งนี้อย่างกระชับมากขึ้นในข้อความของเขาซึ่งมาถึงหลังจากที่ฉันเขียนทั้งหมดนี้

- - Guido van Rossum (โฮมเพจ: http://www.python.org/~guido/ )

ความเข้าใจของฉันเกี่ยวกับเรื่องนี้คือในบางกรณีสัญกรณ์นำหน้าจะมีความหมายมากกว่า (กล่าวคือ Duck.quack มีความหมายมากกว่าการต้มตุ๋น (Duck) จากมุมมองทางภาษา) และอีกครั้งฟังก์ชั่นอนุญาตสำหรับ "อินเทอร์เฟซ"

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

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


2
ฉันคิดเสมอว่ามันเป็นไปตามอำเภอใจ การพิมพ์เป็ดช่วยให้ "อินเทอร์เฟซ" โดยนัยไม่ได้สร้างความแตกต่างมากนักไม่ว่าคุณจะมีX.frobหรือX.__frob__และยืนfrobอิสระ
Cat Plus Plus

2
แม้ว่าฉันจะเห็นด้วยกับคุณเป็นส่วนใหญ่ แต่โดยหลักการแล้วคำตอบของคุณไม่ใช่ Pythonic โปรดจำไว้ว่า "เมื่อเผชิญกับความคลุมเครือจงปฏิเสธสิ่งล่อใจที่จะคาดเดา" (แน่นอนว่ากำหนดเวลาจะเปลี่ยนสิ่งนี้ แต่ฉันกำลังทำสิ่งนี้เพื่อความสนุกสนาน / พัฒนาตนเอง)
Ceasar Bautista

นี่เป็นสิ่งหนึ่งที่ฉันไม่ชอบเกี่ยวกับ python ฉันรู้สึกว่าคุณกำลังจะบังคับให้ cast การพิมพ์เช่น int เป็นสตริงแล้วทำให้เป็นวิธีการ มันน่ารำคาญที่ต้องใส่ไว้ใน parens และเสียเวลา
Matt

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

1
"Zen of Python ระบุว่าควรมีวิธีเดียวเท่านั้นที่จะทำสิ่งต่างๆ"ยกเว้นจะไม่มี
61

คำตอบ:


84

กฎทั่วไปของฉันคือ - การดำเนินการกับวัตถุหรือโดยวัตถุ?

หากทำโดยวัตถุควรเป็นการดำเนินการของสมาชิก หากสามารถนำไปใช้กับสิ่งอื่นได้เช่นกันหรือทำโดยสิ่งอื่นกับวัตถุก็ควรเป็นฟังก์ชัน (หรืออาจเป็นสมาชิกของสิ่งอื่น)

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

class duck: 
    def __init__(self):pass
    def eat(self, o): pass 
    def crap(self) : pass
    def die(self)
    ....

ในบริบทของการเปรียบเทียบ "วัตถุคือของจริง" การเพิ่มวิธีการคลาสสำหรับสิ่งที่วัตถุทำได้นั้น "ถูกต้อง" นั้น "ถูกต้อง" บอกว่าฉันอยากจะฆ่าเป็ดฉันจะเพิ่ม. คิล () ให้เป็ดไหม? ไม่ ... เท่าที่ฉันรู้ว่าสัตว์ไม่ฆ่าตัวตาย ดังนั้นถ้าฉันต้องการฆ่าเป็ดฉันควรทำดังนี้:

def kill(o):
    if isinstance(o, duck):
        o.die()
    elif isinstance(o, dog):
        print "WHY????"
        o.die()
    elif isinstance(o, nyancat):
        raise Exception("NYAN "*9001)
    else:
       print "can't kill it."

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

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

TL; DR : สิ่งที่ @ ไบรอันพูด หากดำเนินการกับอินสแตนซ์และต้องการเข้าถึงข้อมูลที่อยู่ภายในอินสแตนซ์คลาสควรเป็นฟังก์ชันสมาชิก


ดังนั้นในระยะสั้นฟังก์ชันที่ไม่ใช่สมาชิกจะทำงานบนวัตถุที่ไม่เปลี่ยนรูปวัตถุที่เปลี่ยนแปลงไม่ได้ใช้ฟังก์ชันสมาชิก? (หรือนี่เป็นการวางนัยทั่วไปที่เข้มงวดเกินไปหรือไม่สิ่งนี้ใช้ได้กับบางประเภทเท่านั้นเพราะไม่เปลี่ยนรูปแบบไม่มีสถานะ)
Ceasar Bautista

1
จากมุมมอง OOP ที่เข้มงวดฉันคิดว่ามันยุติธรรม เนื่องจาก Python มีทั้งตัวแปรสาธารณะและส่วนตัว (ตัวแปรที่มีชื่อขึ้นต้นด้วย __) และให้การป้องกันการเข้าถึงที่รับประกันเป็นศูนย์ซึ่งแตกต่างจาก Java จึงไม่มีความสมบูรณ์เพียงเพราะเรากำลังถกเถียงกันเรื่องภาษาที่อนุญาต อย่างไรก็ตามในภาษาที่อนุญาตน้อยกว่าเช่น Java โปรดจำไว้ว่าฟังก์ชัน getFoo () ad setFoo () เป็นบรรทัดฐานดังนั้นความไม่เปลี่ยนรูปจึงไม่แน่นอน รหัสลูกค้าไม่ได้รับอนุญาตให้ทำการมอบหมายให้กับสมาชิก
arrdem

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

1
@CeasarBautista ใช่เบนมีประเด็น มีโรงเรียน "หลัก" สามแห่งในการออกแบบโค้ด 1) ไม่ได้ออกแบบ 2) OOP และ 3) ใช้งานได้ ในรูปแบบการใช้งานไม่มีสถานะใด ๆ เลย นี่เป็นวิธีที่ฉันเห็นโค้ด python ส่วนใหญ่ออกแบบมาต้องใช้อินพุตและสร้างเอาต์พุตที่มีผลข้างเคียงน้อย จุดของ OOP คือว่าทุกอย่างมีรัฐ คลาสเป็นคอนเทนเนอร์สำหรับสถานะและฟังก์ชัน "สมาชิก" จึงเป็นโค้ดตามสถานะและผลข้างเคียงซึ่งโหลดสถานะที่กำหนดไว้ในคลาสเมื่อใดก็ตามที่เรียกใช้ Python มีแนวโน้มที่จะทำงานแบบลีนดังนั้นการตั้งค่ารหัสที่ไม่ใช่สมาชิก
arrdem

1
กิน (ตัวเอง) อึ (ตัวเอง) ตาย (ตัวเอง) ฮ่า ๆ ๆ
ปิติ

27

ใช้ชั้นเรียนเมื่อคุณต้องการ:

การใช้ประโยชน์จาก - 1) แยกรหัสจากรายละเอียดการดำเนินการเรียกนามธรรมและencapsulation

2) เมื่อคุณต้องการที่จะทดแทนสำหรับวัตถุอื่น ๆ - การใช้ประโยชน์จากความแตกต่าง

3) เมื่อคุณต้องการที่จะนำมาใช้สำหรับวัตถุที่คล้ายกัน - การใช้ประโยชน์จากการถ่ายทอดทางพันธุกรรม

ใช้ฟังก์ชันสำหรับการเรียกที่เหมาะสมกับอ็อบเจ็กต์ประเภทต่างๆเช่นฟังก์ชัน builtin lenและreprใช้กับอ็อบเจ็กต์หลายชนิด

ดังที่กล่าวมาบางครั้งทางเลือกก็ขึ้นอยู่กับเรื่องของรสนิยม คิดในแง่ของสิ่งที่สะดวกและอ่านง่ายที่สุดสำหรับการโทรทั่วไป ตัวอย่างเช่นจะดีกว่า(x.sin()**2 + y.cos()**2).sqrt()หรือsqrt(sin(x)**2 + cos(y)**2)?


7

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

ในตัวอย่างเฉพาะของคุณคุณต้องการให้มีลักษณะดังนี้:

chessboard = Chessboard()
...
chessboard.get_king_moves()

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


2
คุณอธิบายได้ไหมว่าทำไมคุณถึงตั้งค่าเริ่มต้นเป็นวิธีการบนฟังก์ชัน? (และคุณช่วยอธิบายได้ไหมว่ากฎนั้นยังสมเหตุสมผลในกรณีของสแต็กและคิว / ป๊อปและวิธีการกด)
Ceasar Bautista

11
กฎทั่วไปนั้นไม่สมเหตุสมผล ไลบรารีมาตรฐานสามารถเป็นแนวทางในการใช้คลาสเทียบกับฟังก์ชันได้ heapqและคณิตศาสตร์เป็นฟังก์ชันเนื่องจากทำงานบนวัตถุ python ปกติ (ลอยและแสดงรายการ) และเนื่องจากไม่จำเป็นต้องรักษาสถานะที่ซับซ้อนเช่นเดียวกับโมดูลสุ่ม
Raymond Hettinger

1
คุณกำลังบอกว่ากฎไม่มีเหตุผลเพราะไลบรารีมาตรฐานละเมิดหรือไม่? ฉันไม่คิดว่าข้อสรุปนั้นสมเหตุสมผล ประการแรกกฎง่ายๆก็คือมันไม่ใช่กฎที่แน่นอน นอกจากนี้ส่วนใหญ่ของไลบรารีมาตรฐานจะเป็นไปตามกฎง่ายๆนั้น OP กำลังมองหาแนวทางง่ายๆและฉันคิดว่าคำแนะนำของฉันเหมาะอย่างยิ่งสำหรับคนที่เพิ่งเริ่มต้น อย่างไรก็ตามฉันขอขอบคุณในมุมมองของคุณ
Bryan Oakley

STL มีเหตุผลที่ดีที่จะทำเช่นนั้น เห็นได้ชัดว่าสำหรับคณิตศาสตร์และร่วมมันไม่มีประโยชน์ที่จะมีคลาสเนื่องจากเราไม่มีสถานะใด ๆ (ในภาษาอื่นคือคลาสที่มีฟังก์ชันคงที่เท่านั้น) สำหรับสิ่งที่ทำงานบนภาชนะต่างๆเช่นพูดlen()ได้ก็อาจเป็นที่ถกเถียงกันอยู่ว่าการออกแบบนั้นสมเหตุสมผลแม้ว่าโดยส่วนตัวแล้วฉันคิดว่าฟังก์ชั่นต่างๆก็ไม่ได้แย่เกินไปเช่นกัน - เราก็มีการประชุมอื่นที่len()ต้องคืนค่า จำนวนเต็ม (แต่ด้วยปัญหาเพิ่มเติมทั้งหมดของ backcomp ฉันจะไม่สนับสนุนสิ่งนั้นสำหรับ python เช่นกัน)
Voo

-1 เนื่องจากคำตอบนี้เป็นไปตามอำเภอใจโดยสิ้นเชิง: คุณพยายามแสดงให้เห็นว่า X ดีกว่า Y โดยสมมติว่า X ดีกว่า Y
สำคัญกับ

7

ฉันมักจะนึกถึงสิ่งของเหมือนคน

แอตทริบิวต์ได้แก่ ชื่อของบุคคลความสูงขนาดรองเท้า ฯลฯ

วิธีการและหน้าที่คือการดำเนินการที่บุคคลสามารถดำเนินการได้

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

หากการดำเนินการจะปฏิบัติตามคน (เช่นการรับประทานอาหาร, การเดิน, ... ) หรือต้องมีบางสิ่งบางอย่างที่ไม่ซ้ำกับคน ๆ นี้จะมีส่วนร่วม (เช่นการเต้นรำเขียนหนังสือ, ... ) แล้วมันควรจะเป็นวิธีการ

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


แต่คุณสามารถวัดความสูงคนใดคนเก่าดังนั้นโดยตรรกะที่มันควรจะเป็นheight(person)ไม่person.height?
endolith

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

@endolith ในทางกลับกันหากบุคคลนั้นเป็นเด็กที่เติบโตและเปลี่ยนแปลงความสูงจะเห็นได้ชัดว่าให้วิธีการดูแลสิ่งนั้นไม่ใช่หน้าที่
เจริญงอกงาม

สิ่งนี้ไม่ถือเป็นความจริง ถ้าคุณมีare_married(person1, person2)ล่ะ? แบบสอบถามนี้เป็นข้อมูลทั่วไปและควรเป็นฟังก์ชันไม่ใช่วิธีการ
Pithikos

@Pithikos แน่นอน แต่นั่นยังเกี่ยวข้องกับมากกว่าแค่แอตทริบิวต์หรือการกระทำที่ดำเนินการกับวัตถุ (บุคคล) เดียว แต่เป็นความสัมพันธ์ระหว่างวัตถุสองชิ้น
เจริญเติบโต

5

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

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

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

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


0

คุณอาจพูดแบบนั้น "เมื่อเผชิญกับความคลุมเครือจงปฏิเสธสิ่งล่อใจที่จะคาดเดา"

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

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

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