มีเหตุผลที่ดีที่จะทำให้ฟังก์ชั่นที่บริสุทธิ์ไม่ใช่แบบสาธารณะหรือไม่?


25

ฉันมีการอภิปรายเล็กน้อยเกิดขึ้นกับเพื่อนร่วมงาน มีเหตุผลที่ดีที่จะซ่อน / ห่อหุ้มฟังก์ชั่นที่บริสุทธิ์หรือไม่?

โดย "pure" ฉันหมายถึงคำจำกัดความของวิกิพีเดีย :

  • ส่งคืนผลลัพธ์เดียวกันจากอินพุตเดียวกันเสมอ (เพื่อประโยชน์ในการสนทนาFoo Create(){ return new Foo(); }นี้ถือว่าไม่บริสุทธิ์หากFooไม่มีความหมายตามตัวอักษร)
  • ห้ามใช้สถานะที่ไม่แน่นอน (ยกเว้นตัวแปรโลคัล) หรือ I / O
  • ไม่ก่อให้เกิดผลข้างเคียง

26
อาจมีการโต้แย้งที่ไม่ให้สมาชิกฟังก์ชันของคลาสเลย
Pieter B

6
@PieterB - แน่นอนว่าไม่ใช่ทุกภาษาที่รองรับและบางภาษาอนุญาตให้โมดูลภายในแม้สำหรับฟังก์ชั่นฟรี
Telastyn

3
คุณมีความคิดเห็นอย่างไร? ฉันไม่คิดว่าความบริสุทธิ์ของฟังก์ชั่นนั้นเกี่ยวข้องกับว่าเป็นของ API สาธารณะหรือไม่
Andres F.

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

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

คำตอบ:


76

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


33
+1 สมาชิกสาธารณะของชั้นเรียนของคุณคือ API ไม่ใช่คำถามที่ว่า "จะเป็นอันตรายต่อฉันหรือไม่หากเป็นแบบสาธารณะ" แต่แทนที่จะเป็น "ควรเป็นส่วนหนึ่งของ API หรือไม่"
Ordous

1
สิ่งเดียวที่ฉันจะเพิ่มคือถ้าคุณเริ่มเห็นฟังก์ชั่นที่คล้ายกันโผล่ขึ้นมาในสถานที่อื่น ๆ refactor มันในชั้นเรียนอื่นเพื่อให้หลายชั้นสามารถใช้งานได้ หรือถ้านั่นเป็นข้อกังวลที่จะเริ่มต้นด้วยให้นิยามมันในคลาสอื่นเพื่อเริ่มต้นด้วย
jpmc26

1
ฉันจะประทับตราชั้นเรียนสาธารณะที่ไม่ได้ตั้งใจที่จะขยายเช่นกัน
Den

+1 สำหรับการชี้ให้เห็นว่าการซ่อนหรือแสดงฟังก์ชั่น (หรือคลาส) เป็นคำถามหลักในการปกป้องและบำรุงรักษา API และไม่เกี่ยวข้องกับประเภทของรหัส
มาร์โก

42

คำถามย้อนหลัง

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

กล่าวอีกนัยหนึ่ง - อย่าถามว่า "ทำไมฉันถึงทำให้เป็นส่วนตัว?" ถาม: "ทำไมฉันถึงต้องเปิดเผยสู่สาธารณะ"

เมื่อมีข้อสงสัยอย่าเปิดเผย มันเป็นเหมือนมีดโกนของ Ockham - อย่ามีสิทธิ์ทวีคูณเกินความจำเป็น

แก้ไข:การตอบโต้การโต้เถียงที่นำเสนอโดย @Telastyn ในความคิดเห็น (เพื่อหลีกเลี่ยงการอภิปรายเพิ่มเติมที่นั่น):

ฉันเคยได้ยินเรื่องนี้เมื่อเวลาผ่านไปและแม้กระทั่งดำเนินการในบางเวลา แต่จากประสบการณ์ของฉันสิ่งต่าง ๆ มีแนวโน้มที่จะเป็นส่วนตัวเกินไป

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

แต่protectedจะพอเพียง - และก็ยังไม่เป็นสาธารณะ

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

ถ้ามันกลายเป็นปัญหาคุณก็แค่เปิดเผยสู่สาธารณะ! มีความจำเป็นที่ฉันพูดถึง :)

ประเด็นของฉันคือคุณไม่ควรทำในกรณี (YAGNI และทั้งหมด)

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


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

3
@Telastyn IMHO ที่ดูเหมือนแอปพลิเคชั่นต้องทนทุกข์ทรมานจากการออกแบบผิดพลาด ถ้าคุณพบว่าตัวเองมีความโน้มเอียงที่จะเปิดเผยวิธีการเพราะคุณจะต้องเรียกมันข้ามเส้นทางรหัสที่ไม่ต่อเนื่องก็อาจเป็นสัญญาณว่าวิธีนี้ควรจะแยกย่อยออกเป็นโมดูลของตัวเองที่สามารถฉีดหรือรวมที่เหมาะสมโดยเฉพาะอย่างยิ่งถ้าหากมันเป็นฟังก์ชั่นที่บริสุทธิ์ .
สิงห์

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

5
@Telastyn ในความคิดของฉันนั่นเป็นอาการของปรัชญา "ทุกอย่างเป็นวัตถุ / คลาส" รวมกับความจริงที่ว่าบางภาษา OOP ไม่ได้มีประเภทข้อมูลประกอบอื่นนอกเหนือจากชั้นเรียน ทันทีที่มีคนต้องการผ่านสองค่าในเวลาเดียวกันพวกเขาก็จบการเขียนชั้นเรียนจากนั้นผู้ร่วมงานและซอฟต์แวร์ตรวจสอบสไตล์จะบอกให้คุณทำให้เขตข้อมูลเหล่านั้นเป็นส่วนตัว
Doval

@Tastastyn ถูกต้อง สิ่งที่ฉันหมายถึงคือถ้าวิธีการ 'integerLessThan' ของคุณเริ่มต้นจากรายละเอียดการใช้งานที่ห่อหุ้มของวิธีสาธารณะ แต่คุณพบว่าคุณต้องเรียกใช้วิธีส่วนตัวในที่อื่นนั่นอาจเป็นสัญญาณว่า module / package / class เพื่อให้สามารถอิมพอร์ตได้อย่างอิสระจากตรรกะที่เรียกใช้ เพียงเผยแพร่วิธีการตามที่เป็นอยู่หมายความว่าวิธีการนั้นตั้งอยู่โดยพลการในโมดูลแรกที่คุณพบว่ามีประโยชน์
สิงห์

6

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


5

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

นี่เป็นเพียงตัวอย่างหนึ่งของกรณีที่การมองเห็นอาจทำให้เกิดปัญหาได้

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

เนื่องจากนี่คือฟังก์ชั่นแท้ (สตริงเข้ามาเปลี่ยนมันอย่างใดกลับสตริงใหม่) มันอาจจะเป็นสาธารณะหรือส่วนตัวโดยไม่มีผล หรือมันได้หรือไม่

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

โดยการรักษาฟังก์ชั่นส่วนตัวไม่มีใครเคยมีโอกาสที่จะพึ่งพารหัสที่ไม่ได้เป็นส่วนหนึ่งของความรับผิดชอบเดียวของชั้นเรียน


2
ฉันจะยืนยันว่ามันควรจะมีฟังก์ชั่นที่เป็นส่วนหนึ่งของความรับผิดชอบเดียวไม่เพียง แต่เปิดเผย
Telastyn

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

อย่างแน่นอน แนวทางเป็นแนวทางไม่ใช่กฎ
Telastyn

@snowman ใน non java คุณเพียงแค่สร้างไลบรารีของฟังก์ชั่น
Pieter B

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