วัฒนธรรม Grokking Java - ทำไมสิ่งต่าง ๆ ถึงหนักนัก มันเหมาะกับอะไร? [ปิด]


288

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

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

ตัวอย่างที่สมบูรณ์แบบน้อยที่สุดมีอยู่ในคำถาม Stack Overflow ที่ฉันเริ่มต้น: https://stackoverflow.com/questions/43619566/returning-a-result-with-several-values-the-java-way/43620339

ฉันมีงาน - แยก (จากสตริงเดียว) และจัดการชุดสามค่า ใน Python มันเป็นหนึ่งซับ (tuple) ใน Pascal หรือ C-5 ซับเร็กคอร์ด / struct

ตามคำตอบที่เทียบเท่าของ struct มีอยู่ในไวยากรณ์ Java และสามมีอยู่ในห้องสมุด Apache ที่ใช้กันอย่างแพร่หลาย - แต่วิธีที่ "ถูกต้อง" ในการทำมันเป็นจริงโดยการสร้างชั้นแยกสำหรับค่าพร้อมกับ getters และ setters มีคนใจดีมากที่ให้ตัวอย่างที่สมบูรณ์ มันเป็นรหัสของ 47 บรรทัด (ก็ดีบางบรรทัดเหล่านี้เป็นช่องว่าง)

ฉันเข้าใจว่าชุมชนการพัฒนาขนาดใหญ่น่าจะไม่ "ผิด" นี่เป็นปัญหาที่ฉันเข้าใจ

Python จะปรับให้เหมาะสมสำหรับการอ่าน (ซึ่งในปรัชญานั้นจะนำไปสู่การบำรุงรักษา) และหลังจากนั้นความเร็วในการพัฒนา การปฏิบัติที่เหมาะสมที่สุดสำหรับการใช้ทรัพยากร การปฏิบัติ Java เพิ่มประสิทธิภาพสำหรับอะไร? การคาดเดาที่ดีที่สุดของฉันคือความยืดหยุ่น (ทุกอย่างควรอยู่ในสถานะพร้อมสำหรับโครงการล้าน LOC) แต่มันเป็นการคาดเดาที่อ่อนแอมาก


1
จะไม่ตอบคำถามด้านเทคนิคของคำถาม แต่ยังอยู่ในบริบท: softwareengineering.stackexchange.com/a/63145/13899
Newtopian

74
คุณสามารถเพลิดเพลินกับการประพันธ์เรียงความของ Steve Yegge ในราชอาณาจักรคำนาม
Colonel Panic

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

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

1
เหตุผลที่ Java เป็นมาตรฐานจริงเนื่องจากเป็นสิ่งที่ถูกต้อง มันถูกสร้างขึ้นเป็นครั้งแรกโดยคนจริงจังที่มีเคราก่อนที่เคราจะทันสมัย หากคุณคุ้นเคยกับการเคาะเชลล์สคริปต์เพื่อจัดการไฟล์ Java ดูเหมือนจะป่องมากเกินไป แต่ถ้าคุณต้องการสร้างคลัสเตอร์เซิร์ฟเวอร์สำรองคู่ที่สามารถให้บริการ 50 ล้านคนต่อวันได้รับการสนับสนุนโดยการแคช Redis แบบคลัสเตอร์ระบบการเรียกเก็บเงิน 3 ระบบและคลัสเตอร์ฐานข้อมูล Oracle 20M ปอนด์คุณจะไม่ใช้งูหลามแม้ว่าจะเข้าถึง ฐานข้อมูลใน Python มีโค้ดน้อยกว่า 25 บรรทัด
Richard

คำตอบ:


237

ภาษาจาวา

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

เดิมที Java ถูกสร้างขึ้นเป็น C ที่ปรับปรุงขึ้นเล็กน้อยด้วย OO เช่น Java มีไวยากรณ์ยุค 70 นอกจากนี้ Java ยังมีความระมัดระวังในการเพิ่มคุณสมบัติเพื่อรักษาความเข้ากันได้แบบย้อนหลังและช่วยให้สามารถทดสอบเวลาได้ หาก Java ได้เพิ่มฟีเจอร์ที่ทันสมัยเช่นตัวอักษร XML ในปี 2005 เมื่อ XML นั้นเป็นภาษาที่เดือดดาลภาษาจะเต็มไปด้วยคุณสมบัติผีที่ไม่มีใครใส่ใจและ จำกัด การวิวัฒนาการของ 10 ปีต่อมา ดังนั้น Java จึงขาดไวยากรณ์ที่ทันสมัยจำนวนมากเพื่อแสดงแนวคิดที่ไม่ถูกต้อง

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


วัฒนธรรมชวา

ประวัติความเป็นมาของการพัฒนา Java ขององค์กรได้นำพาเราไปสู่วัฒนธรรมที่เราเห็นทุกวันนี้ ในช่วงปลายยุค 90 / ต้นยุค 00 ชวากลายเป็นภาษาที่ได้รับความนิยมอย่างมากสำหรับแอปพลิเคชันธุรกิจฝั่งเซิร์ฟเวอร์ ก่อนหน้านั้นแอปพลิเคชันเหล่านั้นส่วนใหญ่จะเขียนแบบเฉพาะกิจและรวมข้อกังวลที่ซับซ้อนมากมายเช่น HTTP API, ฐานข้อมูลและการประมวลผลฟีด XML

ในยุค 00 เป็นที่ชัดเจนว่าหลาย ๆ แอปพลิเคชันเหล่านี้มีจำนวนมากที่เหมือนกันและเฟรมเวิร์กในการจัดการข้อกังวลเหล่านี้เช่น Hibernate ORM, Xerces XML parser, JSPs และ servlet API และ EJB เป็นที่นิยม อย่างไรก็ตามในขณะที่เฟรมเวิร์กเหล่านี้ลดความพยายามในการทำงานในโดเมนเฉพาะที่พวกเขาตั้งให้เป็นอัตโนมัติพวกเขาต้องการการกำหนดค่าและการประสานงาน ในเวลาไม่ว่าด้วยเหตุผลใดก็ตามการเขียนกรอบการทำงานเพื่อรองรับกรณีการใช้งานที่ซับซ้อนมากที่สุดทำให้ห้องสมุดเหล่านี้มีความซับซ้อนในการติดตั้งและบูรณาการ และเมื่อเวลาผ่านไปพวกเขาก็เพิ่มความซับซ้อนมากขึ้นเมื่อสะสมคุณลักษณะ การพัฒนาองค์กร Java ค่อย ๆ เพิ่มขึ้นเรื่อย ๆ เกี่ยวกับการเชื่อมต่อไลบรารีบุคคลที่สามเข้าด้วยกัน

ในที่สุดการกำหนดค่าที่น่าเบื่อและการจัดการเครื่องมือขององค์กรกลายเป็นเรื่องเจ็บปวดมากพอที่เฟรมเวิร์กส่วนใหญ่คือ Spring Framework เข้ามาจัดการการจัดการ คุณสามารถกำหนดค่าทั้งหมดของคุณไว้ในที่เดียวทฤษฎีไปแล้วเครื่องมือการกำหนดค่าก็จะกำหนดค่าชิ้นและเชื่อมต่อเข้าด้วยกัน น่าเสียดายที่ "เฟรมเวิร์กเฟรมเวิร์ก" เหล่านี้เพิ่มความเป็นนามธรรมและความซับซ้อนให้กับส่วนบนของแว็กซ์ทั้งหมด

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


15
สิ่งที่ตลกคือภาษาอื่นดูเหมือนว่าจะมี "java-isms" ฟีเจอร์ของ PHP OO นั้นได้รับแรงบันดาลใจอย่างมากจากจาวาและในปัจจุบัน JavaScript มักถูกวิพากษ์วิจารณ์ว่ามีเฟรมเวิร์กจำนวนมากและยากที่จะรวบรวมการอ้างอิงทั้งหมดและเริ่มต้นแอปพลิเคชันใหม่
มาร์คัส

14
@marcus อาจเป็นเพราะบางคนในที่สุดก็ได้เรียนรู้สิ่งที่ "ไม่ต้องพลิกโฉมพวงมาลัย" การพึ่งพาเป็นค่าใช้จ่ายในการไม่หมุนพวงมาลัยใหม่ทั้งหมด
Walfrat

9
"Terse"มักแปลเป็น arcane, "ฉลาด" , code-golf-ish
Tulains Córdova

7
คำตอบที่ดีและรอบคอบ บริบททางประวัติศาสตร์ ค่อนข้างไม่ได้ปันส่วน ทำได้ดีมาก
Cheezmeister

10
@ TulainsCórdovaฉันยอมรับว่าเราควร "หลีกเลี่ยง ... เทคนิคที่ชาญฉลาดเช่นโรคระบาด" (Donald Knuth) แต่นั่นไม่ได้แปลว่าการเขียนforลูปเมื่อ a mapจะเหมาะสมกว่า (และสามารถอ่านได้) มีสื่อที่มีความสุข
Brian McCutchon

73

ฉันเชื่อว่าฉันมีคำตอบสำหรับหนึ่งในประเด็นที่คุณยกขึ้นซึ่งคนอื่นไม่ได้รับ

Java ปรับให้เหมาะสมสำหรับการตรวจหาข้อผิดพลาดโปรแกรมเมอร์เวลาคอมไพล์โดยไม่ทำให้สมมติฐานใด ๆ

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

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

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

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

ใน Java มีสองวิธีในการทำเช่นนี้:

  1. ใช้Triplet<A, B, C>เป็นประเภทผลตอบแทน (ซึ่งจริงๆควรจะอยู่ในjava.utilและฉันไม่สามารถจริงๆอธิบายว่าทำไมมันไม่ได้. โดยเฉพาะอย่างยิ่งตั้งแต่ JDK8 แนะนำFunction, BiFunction, Consumer, BiConsumerฯลฯ ... มันก็ดูเหมือนว่าPairและTripletอย่างน้อยจะทำให้รู้สึก. แต่ฉันเชือนแช )

  2. สร้างประเภทค่าของคุณเองสำหรับจุดประสงค์นั้นโดยที่แต่ละฟิลด์มีชื่อและพิมพ์อย่างถูกต้อง

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

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

พิจารณาบางอย่างเช่นนี้ใน typescript (หรือประเภทโฟลว์) ที่การอนุมานประเภทจะใช้แทนการพิมพ์ที่ชัดเจน

function parseDurationInMillis(csvLine){
    // here the developer intends to return a Number, 
    // but actually it's a String
    return csv.firstField();
}

// Compiler infers that parseDurationInMillis is String, so it does
// string concatenation and infers that plusTwoSeconds is String
// Developer actually intended Number
var plusTwoSeconds = 2000 + parseDurationInMillis(csvLine);

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


โปรดทราบว่าตามหลักการ Object Oriented ที่เหมาะสมและการสร้างแบบจำลองที่ขับเคลื่อนด้วยโดเมนกรณีการวิเคราะห์ระยะเวลาในคำถามที่เชื่อมโยงอาจถูกส่งคืนเป็นjava.time.Durationวัตถุซึ่งจะมีความชัดเจนมากขึ้นว่าทั้งสองกรณีข้างต้น


38
การระบุว่า Java ปรับให้เหมาะสมสำหรับความถูกต้องของรหัสอาจเป็นจุดที่ถูกต้อง แต่ดูเหมือนว่าฉัน (การเขียนโปรแกรมภาษาจำนวนมากเมื่อเร็ว ๆ นี้เป็นบิตของจาวา) ที่ภาษาล้มเหลวหรือไม่มีประสิทธิภาพอย่างมาก จริงอยู่ที่ Java นั้นเก่าและมีหลายสิ่งที่ไม่ได้มีอยู่ แต่มีทางเลือกที่ทันสมัยที่ให้การตรวจสอบความถูกต้องที่ดีกว่าเช่น Haskell (และฉันกล้าพูดหรือ Rust หรือ Go ความไม่มั่นคงของ Java ทั้งหมดไม่จำเป็นสำหรับเป้าหมายนี้ - และนอกจากนี้ไม่ได้ที่ทุกคนอธิบายวัฒนธรรม แต่ Solomonoff เปิดเผยว่าวัฒนธรรมคือ BS อยู่แล้ว
tomsmeding

8
ตัวอย่างนั้นไม่ได้แสดงให้เห็นว่าการอนุมานประเภทนั้นเป็นปัญหาเพียงว่าการตัดสินใจของ JavaScript เพื่อให้การแปลงโดยนัยในภาษาแบบไดนามิกนั้นโง่ ภาษาแบบไดนามิกที่มีสติหรือภาษาที่มีการขนานนามแบบคงที่ที่มีประเภทไม่ดีไม่อนุญาต เป็นตัวอย่างสำหรับทั้งสองชนิด: python จะทำการรันไทม์ยกเว้น Haskell จะไม่คอมไพล์
Voo

39
@tomsmeding เป็นเรื่องที่ควรสังเกตว่าข้อโต้แย้งนี้เป็นเรื่องโง่โดยเฉพาะอย่างยิ่งเพราะ Haskell มีความยาวกว่า Java เป็นเวลา 5 ปี Java อาจมีระบบการพิมพ์ แต่ก็ไม่ได้มีการตรวจสอบความถูกต้องที่ทันสมัยเมื่อเปิดตัว
Alexis King

21
“ Java ปรับให้เหมาะสมสำหรับการตรวจจับข้อผิดพลาดในการคอมไพล์เวลา” - ไม่มันให้แต่ตามที่คนอื่น ๆ ระบุไว้แน่นอนว่ามันไม่เหมาะสำหรับมันในแง่ของคำใด ๆ นอกจากเรื่องนี้เป็นสมบูรณ์ไม่เกี่ยวข้องกับคำถาม OP เพราะภาษาอื่น ๆ ที่ทำจริงเพิ่มประสิทธิภาพในการตรวจหาข้อผิดพลาดเวลารวบรวมไวยากรณ์มีน้ำหนักเบามากขึ้นสำหรับสถานการณ์ที่คล้ายกัน ฟุ่มเฟื่อยมากกว่าที่ด้านบนของ Java มีตรงไม่มีอะไรจะทำอย่างไรกับการตรวจสอบรวบรวมเวลาของมัน
Konrad Rudolph

19
@ KonradRudolph ใช่คำตอบนี้ไร้สาระอย่างสมบูรณ์แม้ว่าฉันคิดว่ามันเป็นที่ดึงดูดอารมณ์ ฉันไม่แน่ใจว่าทำไมมันมีคะแนนเสียงมากมาย Haskell (หรืออาจสำคัญกว่านั้น Idris) จะปรับความถูกต้องได้ดีกว่า Java และมี tuples ที่มีไวยากรณ์ที่มีน้ำหนักเบา ยิ่งไปกว่านั้นการกำหนดประเภทข้อมูลเป็นแบบหนึ่งบรรทัดและคุณจะได้รับทุกสิ่งที่ Java ได้รับ คำตอบนี้เป็นข้อแก้ตัวสำหรับการออกแบบภาษาที่ไม่ดีและการใช้คำฟุ่มเฟือยที่ไม่จำเป็น แต่มันฟังดูดีถ้าคุณชอบ Java และไม่คุ้นเคยกับภาษาอื่น
Alexis King

50

Java และ Python เป็นสองภาษาที่ฉันใช้มากที่สุด แต่ฉันมาจากทิศทางอื่น นั่นคือฉันลึกลงไปในโลก Java ก่อนที่ฉันจะเริ่มใช้ Python ดังนั้นฉันจึงอาจช่วยได้ ฉันคิดว่าคำตอบสำหรับคำถามที่มีขนาดใหญ่ขึ้นว่า "ทำไมเรื่องนี้ถึงหนักหน่วง" มาถึง 2 สิ่ง:

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

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

ในกรณีเฉพาะที่คุณพูดถึงไม่มีสิ่งอันดับ ทางออกที่ง่ายคือการสร้างชั้นเรียนที่มีค่าสาธารณะ เมื่อ Java ออกมาครั้งแรกผู้คนทำสิ่งนี้ค่อนข้างสม่ำเสมอ ปัญหาแรกของการทำเช่นนี้คือการปวดหัวในการบำรุงรักษา หากคุณต้องการเพิ่มตรรกะหรือความปลอดภัยของเธรดหรือต้องการใช้ polymorphism อย่างน้อยที่สุดคุณจะต้องสัมผัสทุกคลาสที่โต้ตอบกับวัตถุ 'tuple-esque' ใน Python มีวิธีแก้ปัญหาเช่นนี้__getattr__เป็นต้นดังนั้นจึงไม่น่ากลัว

มีบางอย่างที่ไม่ดี (IMO) รอบนี้ ในกรณีนี้ถ้าคุณต้องการ tuple ฉันถามว่าทำไมคุณถึงทำให้มันเป็นวัตถุที่ไม่แน่นอน คุณควรจะต้องได้รับ getters (ในด้านหมายเหตุฉันเกลียดอนุสัญญา get / set แต่มันคือสิ่งที่มันเป็น.) ฉันคิดว่าคลาสเปล่า (ไม่แน่นอนหรือไม่ได้) จะมีประโยชน์ในบริบทส่วนตัวหรือแพคเกจส่วนตัวใน Java . นั่นคือโดยการ จำกัด การอ้างอิงในโปรเจ็กต์ให้กับคลาสคุณสามารถ refactor ในภายหลังได้ตามต้องการโดยไม่ต้องเปลี่ยนอินเตอร์เฟสสาธารณะของคลาส นี่คือตัวอย่างของวิธีที่คุณสามารถสร้างวัตถุที่ไม่เปลี่ยนรูปแบบได้อย่างง่าย:

public class Blah 
{
  public static Blah blah(long number, boolean isInSeconds, boolean lessThanOneMillis)
  {
    return new Blah(number, isInSeconds, lessThanOneMillis);
  }

  private final long number;
  private final boolean isInSeconds;
  private final boolean lessThanOneMillis;

  public Blah(long number, boolean isInSeconds, boolean lessThanOneMillis)
  {
    this.number = number;
    this.isInSeconds = isInSeconds;
    this.lessThanOneMillis = lessThanOneMillis;
  }

  public long getNumber()
  {
    return number;
  }

  public boolean isInSeconds()
  {
    return isInSeconds;
  }

  public boolean isLessThanOneMillis()
  {
    return lessThanOneMillis;
  }
}

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

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

public class Blah 
{
  public static Blah fromSeconds(long number)
  {
    return new Blah(number * 1000_000);
  }

  public static Blah fromMills(long number)
  {
    return new Blah(number * 1000);
  }

  public static Blah fromNanos(long number)
  {
    return new Blah(number);
  }

  private final long nanos;

  private Blah(long nanos)
  {
    this.nanos = nanos;
  }

  public long getNanos()
  {
    return nanos;
  }

  public long getMillis()
  {
    return getNanos() / 1000; // or round, whatever your logic is
  }

  public long getSeconds()
  {
    return getMillis() / 1000; // or round, whatever your logic is
  }

  /* I don't really know what this is about but I hope you get the idea */
  public boolean isLessThanOneMillis()
  {
    return getMillis() < 1;
  }
}

ความคิดเห็นไม่ได้มีไว้สำหรับการอภิปรายเพิ่มเติม การสนทนานี้ได้รับการย้ายไปแชท
maple_shaft

2
ฉันขอแนะนำให้คุณดู Scala ด้วยความเคารพคุณลักษณะ "Java ที่ทันสมัยยิ่งขึ้น" ...
MikeW

1
@ MikeWa ฉันเริ่มต้นด้วย Scala ย้อนกลับไปในช่วงต้นของการเผยแพร่และมีการใช้งานในฟอรัมสกาล่าชั่วครู่หนึ่ง ฉันคิดว่ามันเป็นความสำเร็จที่ยอดเยี่ยมในการออกแบบภาษา แต่ฉันได้ข้อสรุปว่าไม่ใช่สิ่งที่ฉันกำลังมองหาและเป็นหมุดสี่เหลี่ยมในชุมชนนั้น ฉันควรดูอีกครั้งเพราะอาจมีการเปลี่ยนแปลงอย่างมีนัยสำคัญตั้งแต่เวลานั้น
JimmyJames

คำตอบนี้ไม่ได้ระบุถึงค่าโดยประมาณที่เพิ่มขึ้นโดย OP
ErikE

@ErikE คำว่า "ค่าโดยประมาณ" ไม่ปรากฏในข้อความคำถาม หากคุณสามารถชี้ให้ฉันไปยังส่วนเฉพาะของคำถามที่ฉันไม่ได้พูดถึงฉันสามารถลองทำเช่นนั้นได้
JimmyJames

41

ก่อนที่คุณจะได้รับบ้าเกินไปใน Java โปรดอ่านคำตอบของฉันในโพสต์อื่น ๆ ของคุณ

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

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

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

ตัวอย่างเช่นสมมติว่าคุณเรียนรู้เพิ่มเติมเกี่ยวกับความแม่นยำหรือมาตราส่วนที่จำเป็นสำหรับการสรุประยะเวลาของคุณและการเปรียบเทียบเพื่อให้ทำงานอย่างถูกต้องและคุณพบว่าคุณต้องการธงกลางเพื่อระบุ "ข้อผิดพลาดประมาณ 32 มิลลิวินาที" (ใกล้กับสี่เหลี่ยม รูตของ 1,000 ดังนั้นครึ่งหนึ่งเป็นลอการิทึมระหว่าง 1 และ 1,000) หากคุณผูกมัดตัวเองกับรหัสที่ใช้วิธีดั้งเดิมในการเป็นตัวแทนคุณจะต้องค้นหาทุกที่ในรหัสที่คุณมีis_in_seconds,is_under_1msและเปลี่ยนเป็นis_in_seconds,is_about_32_ms,is_under_1ms. ทุกอย่างจะต้องเปลี่ยนไปทั่วสถานที่! การสร้างคลาสที่มีความรับผิดชอบคือการบันทึกระยะขอบของข้อผิดพลาดเพื่อให้สามารถใช้ที่อื่นได้ปลดปล่อยผู้บริโภคของคุณจากการรู้รายละเอียดว่าขอบของข้อผิดพลาดหรืออะไรก็ตามเกี่ยวกับวิธีที่พวกเขารวมกัน ในขณะนี้ (นั่นคือไม่มีรหัสการบริโภคที่ขอบของข้อผิดพลาดถูกต้องถูกบังคับให้เปลี่ยนเมื่อคุณเพิ่มระยะขอบใหม่ของระดับข้อผิดพลาดในคลาสเนื่องจากระยะขอบเก่าทั้งหมดของข้อผิดพลาดยังคงถูกต้อง)

คำชี้แจงการปิด

การร้องเรียนเกี่ยวกับความหนักเบาของ Java นั้นดูเหมือนจะหายไปเมื่อคุณเข้าใกล้หลักการของ SOLID และ GRASP และวิศวกรรมซอฟต์แวร์ขั้นสูงเพิ่มเติม

ภาคผนวก

ฉันจะเพิ่มอย่างสมบูรณ์ฟรีและไม่ยุติธรรมที่คุณสมบัติอัตโนมัติของ C # และความสามารถในการกำหนดคุณสมบัติ get-only ในตัวสร้างช่วยล้างรหัสยุ่งมากที่ "วิธี Java" จะต้อง (กับเขตข้อมูลสำรองส่วนตัวชัดเจนและฟังก์ชั่น getter / setter) :

// Warning: C# code!
public sealed class ApproximateDuration {
   public ApproximateDuration(int lowMilliseconds, int highMilliseconds) {
      LowMilliseconds = lowMilliseconds;
      HighMilliseconds = highMilliseconds;
   }
   public int LowMilliseconds { get; }
   public int HighMilliseconds { get; }
}

นี่เป็นการนำ Java ไปใช้ข้างต้น:

public final class ApproximateDuration {
  private final int lowMilliseconds;
  private final int highMilliseconds;

  public ApproximateDuration(int lowMilliseconds, int highMilliseconds) {
    this.lowMilliseconds = lowMilliseconds;
    this.highMilliseconds = highMilliseconds;
  }

  public int getLowMilliseconds() {
    return lowMilliseconds;
  }

  public int getHighMilliseconds() {
    return highMilliseconds;
  }
}

ตอนนี้มันสะอาดแล้ว สังเกตการใช้สิ่งที่เปลี่ยนไม่ได้ที่สำคัญและตั้งใจ - นี่เป็นสิ่งสำคัญสำหรับชั้นเรียนที่มีคุณค่าประเภทนี้

สำหรับเรื่องนี้คลาสนี้ยังเป็นตัวเลือกที่ดีสำหรับการเป็นstructประเภทค่า การทดสอบบางอย่างจะแสดงว่าการสลับเป็นโครงสร้างมีผลประโยชน์ด้านเวลาทำงานหรือไม่ (ทำได้)


9
ฉันคิดว่านี่เป็นคำตอบที่ฉันโปรดปราน ฉันพบว่าเมื่อฉันส่งเสริมชั้นเรียนผู้ถือใบปลิวเส็งเคร็งเช่นนี้เป็นสิ่งที่โตขึ้นมันจะกลายเป็นบ้านสำหรับความรับผิดชอบที่เกี่ยวข้องทั้งหมดและ zing! ทุกอย่างสะอาดขึ้น! และฉันมักจะเรียนรู้สิ่งที่น่าสนใจเกี่ยวกับพื้นที่ปัญหาในเวลาเดียวกัน เห็นได้ชัดว่ามีทักษะในการหลีกเลี่ยงการใช้วิศวกรรมมากเกินไป แต่ Gosling ไม่ได้โง่เมื่อเขาละทิ้งไวยากรณ์ tuple เหมือนกับ GOTO คำสั่งปิดของคุณยอดเยี่ยม ขอบคุณ!
SusanW

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

@neontapir ใช่ขอบคุณ! ฉันรู้ว่ามันมีชื่อ! :-) แม้ว่าฉันต้องบอกว่าฉันชอบมันเมื่อแนวคิดโดเมนปรากฏขึ้นเองจากการรีแฟคเจอริ่งแรงบันดาลใจ (เช่นนี้!) ... มันเหมือนเมื่อคุณได้รับการแก้ไขปัญหาแรงโน้มถ่วงในศตวรรษที่ 19 โดยการค้นพบดาวเนปจูน .. .
SusanW

@SusanW ฉันเห็นด้วย การปรับเปลี่ยนเพื่อลบล้างความคิดดั้งเดิมอาจเป็นวิธีที่ยอดเยี่ยมในการเปิดเผยแนวคิดโดเมน!
neontapir

ฉันเพิ่มตัวอย่างเวอร์ชัน Java ตามที่กล่าวไว้ ฉันไม่ได้ขึ้นอยู่กับน้ำตาลในประโยคทั้งหมดใน C # ดังนั้นหากมีบางอย่างขาดหายไปให้ฉันรู้
JimmyJames

24

ทั้ง Python และ Java ได้รับการปรับแต่งเพื่อการบำรุงรักษาตามปรัชญาของนักออกแบบของพวกเขา แต่พวกเขามีแนวคิดที่แตกต่างกันมากเกี่ยวกับวิธีการบรรลุเป้าหมายนี้

Python เป็นภาษาแบบหลายกระบวนทัศน์ซึ่งปรับให้เหมาะสมสำหรับความชัดเจนและความเรียบง่ายของรหัส (ง่ายต่อการอ่านและเขียน)

Java คือ (ตามธรรมเนียม) ภาษา OO ที่ใช้คลาสกระบวนทัศน์เดียวซึ่งปรับให้เหมาะสมสำหรับความชัดเจนและความสอดคล้องแม้ในราคาของรหัส verbose มากขึ้น

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

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

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


+1 แต่ตาข่ายนี้มีภาษาที่พิมพ์แบบคงที่กับคลาสเช่น Scala ซึ่งยังพบความต้องการแนะนำสิ่งอันดับ ฉันคิดว่าสิ่งอันดับเป็นเพียงวิธีแก้ปัญหา neater ในบางกรณีแม้แต่ภาษาที่มีชั้นเรียน
Andres F.

@AndresF: คุณหมายถึงอะไรตาข่าย? Scala เป็นภาษาที่แตกต่างจาก Java และมีหลักการออกแบบและสำนวนที่แตกต่างกัน
JacquesB

ฉันหมายถึงมันในการตอบกลับย่อหน้าที่ 5 ของคุณซึ่งเริ่มต้นด้วย "แต่นี่ไม่ตรงกับวัฒนธรรม Java [... ]" อันที่จริงฉันเห็นด้วยการใช้คำฟุ่มเฟือยเป็นส่วนหนึ่งของวัฒนธรรมของ Java แต่การขาดสิ่งอันดับไม่สามารถเป็นเพราะพวกเขา "ใช้คลาสที่ประกาศอย่างชัดเจนแล้ว" - หลังจากทั้งหมด Scala ยังมีคลาสที่ชัดเจน (และแนะนำคลาสเคสที่กระชับมากขึ้น) ยังช่วยให้สิ่งอันดับ! ในท้ายที่สุดฉันคิดว่าเป็นไปได้ว่า Java ไม่ได้แนะนำ tuples ไม่เพียงเพราะคลาสสามารถทำได้เหมือนกัน (ที่มีความยุ่งเหยิงมากขึ้น) แต่ยังเป็นเพราะไวยากรณ์ของมันจะต้องคุ้นเคยกับโปรแกรมเมอร์ C และ C ไม่มี tuples
Andres F.

@AndresF: Scala ไม่มีความเกลียดชังกับวิธีการทำสิ่งต่าง ๆ มันรวมคุณสมบัติจากกระบวนทัศน์การทำงานและจาก OO แบบคลาสสิก มันใกล้กับปรัชญาของ Python มากกว่า
JacquesB

@AndresF .: ใช่ Java เริ่มต้นด้วยไวยากรณ์ใกล้กับ C / C ++ แต่ง่ายขึ้นมาก C # เริ่มต้นเป็นสำเนาที่แน่นอนของ Java แต่ได้เพิ่มคุณสมบัติมากมายในช่วงหลายปีรวมถึงสิ่งอันดับ ดังนั้นจึงเป็นความแตกต่างในปรัชญาการออกแบบภาษา (ต่อมารุ่นของ Java เป็นดูเหมือนจะดันทุรังน้อย แต่ฟังก์ชั่นที่สูงขึ้นการสั่งซื้อถูกปฏิเสธในตอนแรกเพราะคุณสามารถทำเช่นเดียวกันซึ่งการเรียน แต่ตอนนี้พวกเขาได้รับการแนะนำดังนั้นบางทีเราจะเห็นการเปลี่ยนแปลงในปรัชญา...)
JacquesB

16

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

การค้นหาวิธีแก้ไขปัญหาของคุณนั้นดีกว่าแบบฝึกหัดและปัญหาของคุณคือการไม่ส่งคืนค่าสามค่าใน Java อย่างรวดเร็ว:

  • มีอาร์เรย์
  • คุณสามารถส่งคืนอาร์เรย์เป็นรายการในหนึ่งซับ: Arrays.asList (... )
  • หากคุณต้องการให้ด้านวัตถุมีความเป็นไปได้น้อยลงในการต้ม (และไม่มีลอมบอก):

class MyTuple {
    public final long value_in_milliseconds;
    public final boolean is_in_seconds;
    public final boolean is_under_1ms;
    public MyTuple(long value_in_milliseconds,....){
        ...
    }
 }

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

ในที่สุด: ฉันใช้ getters เพราะฉันใช้เครื่องมือซีเรียลไลซ์เซชันมากมาย แต่ฉันไม่ได้เขียนมัน ฉันใช้ลอมบอก: ฉันใช้ทางลัดที่มาจาก IDE ของฉัน


9
ยังคงมีค่าในการทำความเข้าใจสำนวนทั่วไปที่คุณเจอในภาษาต่างๆเนื่องจากพวกมันกลายเป็นมาตรฐานที่เข้าถึงได้ง่ายขึ้น สำนวนเหล่านั้นมีแนวโน้มที่จะตกอยู่ภายใต้หัวข้อของ "การปฏิบัติที่ดีที่สุด" ด้วยเหตุผลใดก็ตาม
Berin Loritsch

3
เฮ้ทางออกที่สมเหตุสมผลของปัญหา ดูเหมือนว่าค่อนข้างสมเหตุสมผลเพียงแค่เขียนคลาส (/ struct) กับสมาชิกสาธารณะเพียงไม่กี่คนแทนที่จะเป็นวิธีการแก้ปัญหา OOP ที่ถูกออกแบบมาอย่างเต็มรูปแบบโดยใช้ [gs] etters
tomsmeding

3
สิ่งนี้นำไปสู่การขยายตัวเนื่องจากไม่เหมือนกับ Python การค้นหาหรือโซลูชันที่สั้นกว่าและหรูหรากว่าไม่ได้รับการสนับสนุน แต่กลับหัวกลับหางคือว่า bloat จะมากหรือน้อยสำหรับนักพัฒนา Java ดังนั้นจึงมีระดับของการบำรุงรักษาที่สูงขึ้นเนื่องจากผู้พัฒนาสามารถแลกเปลี่ยนกันได้มากขึ้นและหากโครงการสองโครงการเข้าร่วมหรือสองทีมแยกออกจากกันโดยไม่ได้ตั้งใจ
Mikhail Ramendik

2
@MikailRamendik เป็นการแลกเปลี่ยนระหว่าง YAGNI และ OOP ออร์โธดอกซ์ OOP บอกว่าควรเปลี่ยนวัตถุทุกชิ้น สิ่งเดียวที่สำคัญคือส่วนต่อประสานสาธารณะของวัตถุ สิ่งนี้ช่วยให้คุณสามารถเขียนโค้ดที่เน้นวัตถุรูปธรรมน้อยลง และเนื่องจากฟิลด์ไม่สามารถเป็นส่วนหนึ่งของอินเทอร์เฟซคุณจึงไม่เคยเปิดเผย ซึ่งจะทำให้การบำรุงรักษาโค้ดง่ายขึ้นในระยะยาว นอกจากนี้ยังช่วยให้คุณสามารถป้องกันสถานะที่ไม่ถูกต้อง ในตัวอย่างดั้งเดิมของคุณเป็นไปได้ที่จะมีวัตถุที่มีทั้ง "<ms" และ "s" ซึ่งไม่เหมือนกัน เลวร้าย.
Luaan

2
@PeterMortensen มันเป็นห้องสมุด Java ที่ทำสิ่งต่างๆมากมายที่ไม่เกี่ยวข้องกัน มันดีมาก ๆ นี่คือคุณสมบัติ
ไมเคิล

11

เกี่ยวกับสำนวนภาษาจาวาโดยทั่วไป:

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

Java ควรง่ายต่อการเรียนรู้สำหรับผู้เริ่มต้น ยิ่งสิ่งที่ชัดเจนคือยิ่งยากที่จะพลาดรายละเอียดที่สำคัญ ความมหัศจรรย์น้อยลงเกิดขึ้นซึ่งยากสำหรับผู้เริ่มต้นที่จะเข้าใจ


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

คุณสามารถลดสำเร็จรูปได้ด้วยเครื่องมืออย่างลอมบอก:

@Value
class MyTuple {
    long value_in_milliseconds;
    boolean is_in_seconds;
    boolean is_under_1ms;
}

5
นอกจากนี้ยังเป็นโครงการ AutoValue ของ Google: github.com/google/auto/blob/master/value/userguide/index.md
Ivan

นี่คือเหตุผลที่โปรแกรม Java สามารถดูแลรักษา
Thorbjørn Ravn Andersen

7

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

  1. รหัสห้องสมุดถูกเขียนครั้งเดียว แต่ใช้บ่อยกว่ามาก ในขณะที่มันเป็นการดีที่จะลดค่าใช้จ่ายในการเขียนห้องสมุดให้น้อยลงมันอาจคุ้มค่ากว่าในระยะยาวที่จะเขียนด้วยวิธีที่ลดค่าใช้จ่ายในการใช้ห้องสมุดให้น้อยที่สุด
  2. ซึ่งหมายความว่าประเภทการบันทึกเอกสารด้วยตนเองนั้นยอดเยี่ยม: ชื่อเมธอดช่วยให้ชัดเจนว่าเกิดอะไรขึ้นและสิ่งที่คุณได้รับจากวัตถุ
  3. การพิมพ์สแตติกเป็นเครื่องมือที่มีประโยชน์มากสำหรับการขจัดข้อผิดพลาดบางประเภท แน่นอนว่ามันไม่ได้แก้ไขทุกอย่าง (ผู้คนชอบพูดตลกเกี่ยวกับ Haskell ว่าเมื่อคุณได้รับระบบพิมพ์เพื่อรับรหัสของคุณมันอาจจะถูกต้อง) แต่มันทำให้ง่ายมากที่จะทำสิ่งผิดปกติบางอย่างเป็นไปไม่ได้
  4. การเขียนรหัสห้องสมุดเป็นเรื่องเกี่ยวกับการระบุสัญญา การกำหนดอินเทอร์เฟซสำหรับอาร์กิวเมนต์และประเภทผลลัพธ์ของคุณจะทำให้ขอบเขตของสัญญาของคุณชัดเจนยิ่งขึ้น หากสิ่งที่ยอมรับหรือก่อให้เกิด tuple ไม่มีอะไรบอกได้เลยว่ามันเป็น tuple ที่คุณควรจะได้รับหรือสร้างขึ้นมาจริง ๆ และมีข้อ จำกัด น้อยมากในประเภททั่วไปเช่นนี้ (มันมีองค์ประกอบที่ถูกต้องหรือไม่? เป็นประเภทที่คุณคาดหวังหรือไม่)

คลาส "โครงสร้าง" พร้อมฟิลด์

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

   class ParseResult0 {
      public final long millis;
      public final boolean isSeconds;
      public final boolean isLessThanOneMilli;

      public ParseResult0(long millis, boolean isSeconds, boolean isLessThanOneMilli) {
         this.millis = millis;
         this.isSeconds = isSeconds;
         this.isLessThanOneMilli = isLessThanOneMilli;
      }
   }

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

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

"โครงสร้าง" เป็นอินเทอร์เฟซ

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

   interface ParseResult {
      long getMillis();

      boolean isSeconds();

      boolean isLessThanOneMilli();

      static ParseResult from(long millis, boolean isSeconds, boolean isLessThanOneMill) {
         return new ParseResult() {
            @Override
            public boolean isSeconds() {
               return isSeconds;
            }

            @Override
            public boolean isLessThanOneMilli() {
               return isLessThanOneMill;
            }

            @Override
            public long getMillis() {
               return millis;
            }
         };
      }
   }

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

ด้วยโครงสร้างเช่นผลลัพธ์การแยกวิเคราะห์นี้สัญญาของตัวแยกวิเคราะห์ของคุณจะถูกกำหนดไว้อย่างชัดเจนมาก ใน Python หนึ่ง tuple ไม่แตกต่างจาก tuple อื่น ใน Java การพิมพ์แบบสแตติกสามารถใช้ได้ดังนั้นเราจึงแยกแยะข้อผิดพลาดบางประเภท ตัวอย่างเช่นหากคุณส่งคืน tuple ใน Python และคุณต้องการส่งคืน tuple (มิลลิวินาที, isSeconds, isLessThanOneMilli) คุณสามารถทำได้โดยไม่ตั้งใจ:

return (true, 500, false)

เมื่อคุณหมายถึง:

return (500, true, false)

ด้วยอินเตอร์เฟส Java ชนิดนี้คุณไม่สามารถรวบรวมได้:

return ParseResult.from(true, 500, false);

เลย คุณต้องทำ:

return ParseResult.from(500, true, false);

นั่นเป็นข้อดีของภาษาที่พิมพ์แบบคงที่โดยทั่วไป

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

ทำให้เป็นเรื่องยากที่จะทำผิด

ในตัวอย่างอินเทอร์เฟซด้านบนคุณยังคงมีปัญหาที่คุณสามารถสลับอาร์กิวเมนต์ isSeconds และ isLessThanOneMilli โดยบังเอิญได้เนื่องจากมีชนิดเดียวกัน

ในทางปฏิบัติคุณอาจต้องการใช้ประโยชน์จาก TimeUnit และระยะเวลาเพื่อให้คุณได้ผลลัพธ์ดังนี้:

   interface Duration {
      TimeUnit getTimeUnit();

      long getDuration();

      static Duration from(TimeUnit unit, long duration) {
         return new Duration() {
            @Override
            public TimeUnit getTimeUnit() {
               return unit;
            }

            @Override
            public long getDuration() {
               return duration;
            }
         };
      }
   }

   interface ParseResult2 {

      boolean isLessThanOneMilli();

      Duration getDuration();

      static ParseResult2 from(TimeUnit unit, long duration) {
         Duration d = Duration.from(unit, duration);
         return new ParseResult2() {
            @Override
            public boolean isLessThanOneMilli() {
               return false;
            }

            @Override
            public Duration getDuration() {
               return d;
            }
         };
      }

      static ParseResult2 lessThanOneMilli() {
         return new ParseResult2() {
            @Override
            public boolean isLessThanOneMilli() {
               return true;
            }

            @Override
            public Duration getDuration() {
               throw new IllegalStateException();
            }
         };
      }
   }

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

  ParseResult2 x = ParseResult2.from(TimeUnit.MILLISECONDS, 32);
  ParseResult2 y = ParseResult2.lessThanOneMilli();

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

คำตอบอีกข้อหนึ่งกล่าวว่าลักษณะประเภทองค์กรของ Java หมายถึงเวลาส่วนใหญ่คุณกำลังเขียนไลบรารีอื่น ๆ ที่มีอยู่แล้วหรือเขียนไลบรารีเพื่อให้ผู้อื่นใช้ API สาธารณะของคุณไม่ควรใช้เวลานานในการอ่านเอกสารเพื่อถอดรหัสประเภทผลลัพธ์หากสามารถหลีกเลี่ยงได้

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

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


ฉันใช้ Enum ของตัวเองแทน TimeUnit ในตอนท้ายเพราะฉันเพิ่งเพิ่ม UNDER1MS พร้อมกับหน่วยเวลาจริง ตอนนี้ฉันมีสองฟิลด์ไม่ใช่สามฟิลด์ (ตามทฤษฎีแล้วฉันสามารถใช้ TimeUnit ได้ในทางที่ผิด Nanoseconds แต่มันอาจสร้างความสับสนได้มาก)
Mikhail Ramendik

ฉันไม่ได้สร้างผู้ทะเยอทะยาน แต่ตอนนี้ฉันเห็นว่าผู้ทะเยอทะยานจะอนุญาตให้ฉันโยนข้อยกเว้นได้ถ้าoriginalTimeUnit=DurationTimeUnit.UNDER1MSผู้โทรพยายามอ่านค่ามิลลิวินาที
Mikhail Ramendik

ฉันรู้ว่าคุณพูดถึงมัน แต่จำตัวอย่างของคุณด้วย python tuples เกี่ยวกับ dynamic กับ tuples ที่พิมพ์แบบสแตติก มันไม่ได้พูดอะไรมากเกี่ยวกับสิ่งอันดับตัวเอง คุณสามารถพิมพ์ tuples แบบคงที่ซึ่งจะไม่สามารถรวบรวมได้เนื่องจากฉันแน่ใจว่าคุณรู้ :)
Andres F.

1
@Veedrac ฉันไม่แน่ใจว่าคุณหมายถึงอะไร จุดของฉันคือการที่มันตกลงที่จะเขียนโค้ดห้องสมุดมากขึ้น verbosely เช่นนี้ (แม้ว่ามันจะใช้เวลานาน) เนื่องจากจะมีการใช้เวลามากขึ้นโดยใช้รหัสกว่าการเขียนมัน
Joshua Taylor

1
@Veedrac ใช่มันเป็นเรื่องจริง แต่ผมต้องการรักษาว่ามีคือความแตกต่างระหว่างรหัสที่จะนำกลับมาใช้มีความหมายและรหัสที่จะไม่ เช่นในแพ็คเกจ Java บางคลาสเป็นแบบสาธารณะและใช้งานจากที่อื่น API เหล่านั้นควรได้รับการพิจารณาอย่างดี ภายในห้องเรียนมีชั้นเรียนที่อาจต้องพูดคุยกันเท่านั้น ข้อต่อภายในเหล่านั้นเป็นสถานที่ซึ่งโครงสร้างที่รวดเร็วและสกปรก (เช่นวัตถุ [] ที่คาดว่าจะมีองค์ประกอบสามอย่าง) อาจใช้ได้ สำหรับ API สาธารณะจะต้องมีสิ่งที่มีความหมายและชัดเจนมากกว่านี้
Joshua Taylor

7

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

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

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

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


2
"ไม่มีใคร" ที่จริงแล้วไม่ถูกต้อง - มีเครื่องมือมากมายที่ปรับให้เหมาะสมสำหรับการใช้คำฟุ่มเฟือยน้อยกว่านิพจน์ทั่วไปเป็นตัวอย่างที่ยอดเยี่ยม แต่คุณอาจหมายถึง "ไม่มีใครในโลก Java ที่สำคัญ" และในการอ่านคำตอบนั้นสมเหตุสมผลมากขอบคุณ ความกังวลของฉันเองเกี่ยวกับการใช้คำฟุ่มเฟือยไม่ใช่เวลาที่ใช้ในการเขียนโค้ด แต่เวลาที่ใช้อ่านมัน IDE จะไม่ประหยัดเวลาในการอ่าน แต่ดูเหมือนว่าความคิดคือ 99% ของจำนวนครั้งที่หนึ่งอ่านคำจำกัดความของอินเทอร์เฟซเท่านั้นดังนั้นควรกระชับ?
Mikhail Ramendik

5

ปัจจัยสามอย่างที่แตกต่างกันซึ่งมีส่วนช่วยในสิ่งที่คุณสังเกต

สิ่งอันดับเทียบกับเขตข้อมูลชื่อ

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

ไวยากรณ์ภาษา

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

case class Foo(duration: Int, unit: String, tooShort: Boolean)

เราอาจมีสิ่งนั้น - แต่มีค่าใช้จ่าย: ไวยากรณ์มีความซับซ้อนมากขึ้น แน่นอนว่ามันอาจจะคุ้มค่าสำหรับบางกรณีหรือแม้กระทั่งในกรณีส่วนใหญ่หรือแม้แต่ในกรณีส่วนใหญ่สำหรับ 5 ปีข้างหน้า - แต่มันจะต้องมีการตัดสิน โดยวิธีการนี้เป็นสิ่งที่ดีกับภาษาที่คุณสามารถแก้ไขตัวเอง (เช่นเสียงกระเพื่อม) - และทราบว่าสิ่งนี้จะเป็นไปได้เนื่องจากความเรียบง่ายของไวยากรณ์ แม้ว่าคุณจะไม่ได้ปรับเปลี่ยนภาษาจริง ๆ แต่ไวยากรณ์อย่างง่ายช่วยให้เครื่องมือมีประสิทธิภาพมากขึ้น เช่นหลายครั้งที่ฉันพลาดตัวเลือก refactoring บางตัวสำหรับ Java แต่ไม่ใช่สำหรับ Scala

ปรัชญาภาษา

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

แน่นอนว่ามันเป็นไปได้ที่จะเขียนโค้ดที่ขัดกับปรัชญาภาษาและอย่างที่คุณสังเกตเห็นผลลัพธ์มักจะน่าเกลียด การมีคลาสที่มีเพียงสองสามฟิลด์ใน Java นั้นคล้ายกับการใช้ var ใน Scala ซึ่งเป็นการลดความซับซ้อนของ prlog ให้กับฟังก์ชั่นการทำ unsafePerformIO ใน haskell เป็นต้นคลาส Java ไม่ได้มีความเบา - พวกมันไม่ได้ส่งผ่านข้อมูล . เมื่อสิ่งที่ดูเหมือนยากก็มักจะเป็นผลดีที่จะถอยกลับและดูว่ามีวิธีอื่น ในตัวอย่างของคุณ:

เหตุใดระยะเวลาจึงแยกจากหน่วย มีไลบรารีเวลามากมายที่ให้คุณประกาศช่วงเวลา - บางอย่างเช่นช่วงเวลา (5, วินาที) (ไวยากรณ์จะแตกต่างกันไป) ซึ่งจะช่วยให้คุณทำสิ่งที่คุณต้องการอย่างแข็งแกร่งยิ่งขึ้น บางทีคุณต้องการแปลงมัน - ทำไมตรวจสอบว่าผลลัพธ์ [1] (หรือ [2]?) เป็น 'ชั่วโมง' และคูณด้วย 3600? และสำหรับข้อโต้แย้งที่สาม - จุดประสงค์ของมันคืออะไร? ฉันเดาว่าในบางจุดคุณจะต้องพิมพ์ "น้อยกว่า 1ms" หรือเวลาจริง - นั่นเป็นตรรกะบางอย่างที่เป็นของข้อมูลเวลาตามธรรมชาติ คือคุณควรมีคลาสแบบนี้:

class TimeResult {
    public TimeResult(duration, unit, tooShort)
    public String getResult() {
        if tooShort:
           return "too short"
        else:
           return format(duration)
}

}

หรืออะไรก็ตามที่คุณต้องการจะทำกับข้อมูลดังนั้น encapsulating ตรรกะ

แน่นอนว่าอาจมีกรณีที่วิธีนี้ใช้งานไม่ได้ - ฉันไม่ได้บอกว่านี่เป็นอัลกอริทึมเวทมนต์สำหรับการแปลงผลลัพธ์ tuple ให้เป็นรหัส Java ที่เป็นสำนวน! และอาจมีบางกรณีที่มันน่าเกลียดและแย่มากและบางทีคุณควรจะใช้ภาษาที่แตกต่าง - นั่นเป็นเหตุผลว่าทำไมถึงมีจำนวนมาก!

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


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

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

ส่วนที่สำคัญยิ่งกว่าเกี่ยวกับคำถามนี้คือด้านทั่วไปของสิ่งต่าง ๆ และจากคำตอบทั้งหมดที่ดูเหมือนว่าภาพจะมารวมกัน
Mikhail Ramendik

@ MikailRamendik บางทีการเรียงลำดับของนักสะสมอาจเป็นตัวเลือก - แต่คุณรู้ปัญหาดีกว่า อันที่จริงมันไม่ได้เกี่ยวกับการแก้ปัญหานี้โดยเฉพาะขออภัยถ้าฉันได้รับเล็กน้อยด้าน - จุดหลักของฉันคือภาษาที่กีดกันการใช้ข้อมูล "ง่าย" บางครั้งสิ่งนี้จะช่วยให้คุณคิดทบทวนวิธีการของคุณ - บางครั้ง int ก็เป็นแค่ int
Thanos Tintinidis

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

5

เพื่อความเข้าใจของฉันเหตุผลหลักคือ

  1. การเชื่อมต่อเป็นวิธี Java ขั้นพื้นฐานในการเรียนรู้นามธรรม
  2. Java สามารถคืนค่าเดียวจากวิธี - วัตถุหรืออาร์เรย์หรือค่าดั้งเดิม (int / long / double / float / boolean)
  3. อินเทอร์เฟซไม่สามารถประกอบด้วยเขตข้อมูลวิธีการเท่านั้น หากคุณต้องการเข้าถึงเขตข้อมูลคุณจะต้องผ่านวิธีการ - ดังนั้นจึง getters และ setters
  4. ถ้าเมธอดส่งคืนอินเตอร์เฟสคุณต้องมีคลาสการนำไปใช้เพื่อส่งคืนจริง

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


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

และฉันเห็นด้วยกับ "Tuples ทำงานได้ไม่ดีใน Java" - ดู ถ้าคุณใช้ยาชื่อสามัญมันจะจบลงอย่างรวดเร็ว
Thorbjørn Ravn Andersen

@ ThorbjørnRavnAndersenพวกเขาทำงานได้ดีใน Scala, ภาษาที่พิมพ์แบบคงที่กับยาชื่อสามัญและ tuples ดังนั้นนี่อาจเป็นความผิดของ Java หรือ
Andres F.

@AndresF โปรดทราบว่า "ถ้าคุณใช้ข้อมูลทั่วไป" - ส่วนที่ วิธีที่ Java ทำเช่นนี้ไม่ได้ทำให้ตัวเองมีโครงสร้างที่ซับซ้อนเมื่อเทียบกับ Haskell ฉันไม่ทราบว่า Scala ดีพอที่จะทำการเปรียบเทียบ แต่จริงหรือไม่ที่ Scala อนุญาตให้มีค่าส่งคืนได้หลายค่าหรือไม่ นั่นอาจช่วยได้ค่อนข้างมาก
Thorbjørn Ravn Andersen

@ ThorbjørnRavnAndersenฟังก์ชั่น Scala มีค่าส่งคืนเดียวซึ่งอาจเป็นประเภท tuple (เช่นdef f(...): (Int, Int)เป็นฟังก์ชันfที่ส่งกลับค่าซึ่งเกิดขึ้นเป็น tuple ของจำนวนเต็ม) ฉันไม่แน่ใจว่าข้อมูลทั่วไปใน Java เป็นปัญหากับมัน โปรดทราบว่า Haskell ยังมีประเภทการลบเช่น ฉันไม่คิดว่ามีเหตุผลทางเทคนิคว่าทำไม Java จึงไม่มีสิ่งอันดับ
Andres F.

3

ฉันเห็นด้วยกับ JacquesB ตอบว่า

Java คือ (ตามธรรมเนียม) ภาษา OO ที่ใช้คลาสกระบวนทัศน์เดียวซึ่งปรับให้เหมาะสมที่สุดสำหรับความชัดเจนและความสอดคล้อง

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

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

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

หรือเป็นผู้ชายคนหนึ่งที่ชาญฉลาดจะนำมันมาเป็นเวลานานมากแล้ว ,

วิธีที่ดีที่สุดในการตัดสินภาษาคือดูรหัสที่เขียนโดยผู้เสนอ "Radix enim omnium malorum est cupiditas" - และ Java เป็นตัวอย่างของการเขียนโปรแกรมเชิงเงิน (MOP) อย่างชัดเจน ในฐานะหัวหน้าผู้สนับสนุนของ Java ที่ SGI บอกฉันว่า: "อเล็กซ์คุณต้องไปในที่ที่มีเงิน" แต่ฉันไม่ต้องการที่จะไปที่ที่เป็นเงิน - มันมักจะไม่ได้กลิ่นที่ดีที่นั่น


3

(คำตอบนี้ไม่ใช่คำอธิบายสำหรับ Java โดยเฉพาะ แต่แทนที่จะตอบคำถามทั่วไปของ“ การปฏิบัติที่หนัก [หนัก] จะเหมาะกับอะไร”)

พิจารณาหลักการทั้งสองนี้:

  1. เป็นเรื่องที่ดีเมื่อโปรแกรมของคุณทำสิ่งที่ถูกต้อง เราควรทำให้ง่ายต่อการเขียนโปรแกรมที่ทำสิ่งที่ถูกต้อง
  2. มันไม่ดีเมื่อโปรแกรมของคุณทำสิ่งผิด เราควรทำให้การเขียนโปรแกรมที่ทำสิ่งผิดนั้นยากขึ้น

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

ข้อตกลงใดที่ทำในกรณีพิเศษใด ๆ ขึ้นอยู่กับการสมัครการตัดสินใจของโปรแกรมเมอร์หรือทีมที่มีปัญหาและวัฒนธรรม (ขององค์กรหรือชุมชนภาษา)

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

ตัวอย่างอื่น ๆ ที่มักจะทำให้ระบบของคุณ "หนัก" มากขึ้น:

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

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

ตัวอย่าง: ระบบ Python ภายในของ Google มีแนวโน้มที่จะสร้างสิ่งที่“ หนักหนา” เช่นที่คุณไม่สามารถนำเข้ารหัสของคนอื่นได้คุณต้องประกาศการพึ่งพาในไฟล์ BUILDทีมที่มีรหัสที่คุณต้องการนำเข้าจะต้องมีการประกาศห้องสมุดเป็น มองเห็นรหัสของคุณ ฯลฯ


หมายเหตุ : ทั้งหมดข้างต้นเป็นเพียงเกี่ยวกับเมื่อสิ่งที่มีแนวโน้มที่จะได้รับ "หนัก" ฉันไม่ได้อ้างอย่างแน่นอนว่า Java หรือ Python (ทั้งภาษาของตัวเองหรือวัฒนธรรมของพวกเขา) ทำให้การแลกเปลี่ยนที่ดีที่สุดสำหรับกรณีเฉพาะใด ๆ ; สำหรับคุณที่จะคิด สองลิงค์ที่เกี่ยวข้องกับการแลกเปลี่ยน:


1
แล้วการอ่านโค้ดล่ะ มีการแลกเปลี่ยนอีกครั้งที่นั่น รหัสที่มีน้ำหนักลดลงจากการใช้คาถาแปลกประหลาดและพิธีกรรมมากมายอ่านยาก ด้วย boilerplate และข้อความที่ไม่จำเป็น (และลำดับชั้นของคลาส!) ใน IDE ของคุณมันจะยากที่จะดูว่ารหัสกำลังทำอะไรอยู่ ฉันสามารถดูอาร์กิวเมนต์ที่รหัสไม่ควรจะง่ายต่อการเขียน (ไม่แน่ใจว่าฉันเห็นด้วยกับมัน แต่มีข้อดีบางอย่าง) แต่แน่นอนควรง่ายต่อการเขียนอ่านง่าย เห็นได้ชัดว่ารหัสที่ซับซ้อนสามารถและได้รับการสร้างขึ้นด้วยชวา - มันจะโง่ที่จะเรียกร้องอื่น ๆ - แต่ก็ขอบคุณที่จะฟุ่มเฟื่อยหรือในทั้งๆที่มันได้หรือไม่
Andres F.

@AndresF ฉันแก้ไขคำตอบเพื่อให้ชัดเจนว่าไม่เกี่ยวกับ Java โดยเฉพาะ (ซึ่งฉันไม่ใช่แฟนตัวยง) แต่ใช่แลกเปลี่ยนเมื่ออ่านรหัส: ที่ปลายด้านหนึ่งคุณต้องการที่จะสามารถอ่านได้ง่าย "สิ่งที่รหัสกำลังทำจริง" ตามที่คุณพูด ในอีกด้านหนึ่งคุณต้องการที่จะเห็นคำตอบของคำถามเช่น: รหัสนี้เกี่ยวข้องกับรหัสอื่นอย่างไร อะไรที่เลวร้ายที่สุดที่รหัสนี้สามารถทำได้: สิ่งที่ส่งผลกระทบต่อสถานะอื่นคืออะไร ปัจจัยภายนอกใดที่รหัสนี้อาจขึ้นอยู่กับ? (แน่นอนว่าเราต้องการคำตอบที่รวดเร็วสำหรับชุดคำถามทั้งสองชุด)
ShreevatsaR

2

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

ส่วนหนึ่งของสิ่งที่มีอิทธิพลต่อข้อเสนอแนะคือสิ่งที่ถือว่าอ่านได้และบำรุงรักษาได้ใน Python และ Java แตกต่างกันมาก

  • ใน Python tuple เป็นคุณสมบัติภาษา
  • ทั้งใน Java และ C # tuple คือ (หรือจะเป็น) คุณสมบัติห้องสมุด

ฉันพูดถึง C # เพียงเพราะห้องสมุดมาตรฐานมีชุดของ Tuple <A, B, C, .. n> และมันก็เป็นตัวอย่างที่สมบูรณ์แบบของวิธีการที่ tuples ไม่สะดวกสบายถ้าภาษาไม่รองรับพวกเขาโดยตรง ในเกือบทุกกรณีรหัสของคุณจะสามารถอ่านและบำรุงรักษาได้มากขึ้นถ้าคุณเลือกคลาสเพื่อจัดการกับปัญหา ในตัวอย่างที่เฉพาะเจาะจงในคำถาม Stack Overflow ที่เชื่อมโยงของคุณค่าอื่น ๆ จะแสดงได้อย่างง่ายดายในฐานะผู้ได้รับการคำนวณบนวัตถุที่ส่งคืน

ทางออกที่น่าสนใจที่แพลตฟอร์ม C # ทำซึ่งให้พื้นกลางที่มีความสุขคือแนวคิดของวัตถุนิรนาม (เปิดตัวในC # 3.0 ) ซึ่งทำให้คันคันนี้ค่อนข้างดี น่าเสียดายที่ Java ยังไม่เทียบเท่า

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


4
ในเวอร์ชั่นล่าสุดของ c # tuples ใหม่เป็นพลเมืองชั้นหนึ่งมากกว่าชั้นเรียนห้องสมุด มีเวอร์ชันมากเกินไปที่จะไปถึงที่นั่น
Igor Soloydenko

3 ย่อหน้าสุดท้ายสามารถสรุปได้ว่า "Language X มีคุณสมบัติที่คุณมองหาว่า Java ไม่" และฉันไม่เห็นสิ่งที่พวกเขาเพิ่มในคำตอบ ทำไมพูดถึง C # ในหัวข้อ Python to Java? ไม่ฉันไม่เห็นประเด็น ค่อนข้างแปลกจากคน 20k + rep
Olivier Grégoire

1
ดังที่ฉันพูดว่า "ฉันพูดถึง C # เพียงเพราะ Tuples เป็นคุณสมบัติห้องสมุด" คล้ายกับวิธีที่จะทำงานใน Java หากมี Tuples ในไลบรารีหลัก มันยากที่จะใช้และคำตอบที่ดีกว่าคือเกือบจะมีชั้นเรียนเฉพาะ แม้ว่าวัตถุที่ไม่ระบุชื่อจะทำให้เกิดรอยคันคล้าย ๆ กับสิ่งที่ tuples ออกแบบมา หากไม่มีการสนับสนุนทางภาษาเพื่อสิ่งที่ดีกว่าคุณต้องทำงานกับสิ่งที่บำรุงรักษาได้ดีที่สุด
Berin Loritsch

@IgorSoloydenko อาจมีความหวังสำหรับ Java 9 หรือไม่ นี่เป็นเพียงหนึ่งในคุณสมบัติเหล่านั้นที่เป็นขั้นตอนต่อไปของ lambdas
Berin Loritsch

1
@IgorSoloydenko ฉันไม่แน่ใจว่าเป็นเรื่องจริง (พลเมืองชั้นหนึ่ง) - พวกเขาดูเหมือนจะเป็นส่วนขยายไวยากรณ์ในการสร้างและแกะอินสแตนซ์ของคลาสจากห้องสมุด
Pete Kirkham

0

ฉันคิดว่าหนึ่งในสิ่งสำคัญเกี่ยวกับการใช้คลาสในกรณีนี้คือสิ่งที่ควรจะอยู่ด้วยกัน

ฉันได้มีการสนทนาในทางอื่น ๆ เกี่ยวกับวิธีการโต้แย้ง: พิจารณาวิธีง่ายๆที่คำนวณค่าดัชนีมวลกาย:

CalculateBMI(weight,height)
{
  System.out.println("BMI: " + (( weight / height ) x 703));
}

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

CalculateBMI(Person)
{
  System.out.println("BMI: " + (( Person.weight / Person.height ) x 703));
}

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

เช่นเดียวกับการคืนค่าหลายค่า หากพวกเขาเชื่อมต่ออย่างชัดเจนแล้วส่งคืนแพคเกจเล็ก ๆ อย่างเรียบร้อยและใช้วัตถุหากพวกเขาไม่ได้ส่งคืนค่าหลาย


4
ตกลง แต่สมมติว่าคุณมีงาน (สมมุติ) เพื่อแสดงกราฟ: BMI ขึ้นอยู่กับน้ำหนักของความสูงคงที่เฉพาะเจาะจงอย่างไร จากนั้นคุณจะไม่สามารถทำได้โดยไม่ต้องสร้างบุคคลสำหรับแต่ละจุดข้อมูล และเมื่อนำมันมาถึงสุดขีดคุณไม่สามารถสร้างตัวอย่างของคลาสบุคคลโดยไม่มีวันเกิดและหมายเลขหนังสือเดินทางที่ถูกต้อง ตอนนี้คืออะไร ฉันไม่ downvote ครับมีเป็นเหตุผลที่ถูกต้องสำหรับการผนวกคุณสมบัติร่วมกันในระดับบาง
artem

1
@artem เป็นขั้นตอนต่อไปที่อินเตอร์เฟสเข้ามาเล่น ดังนั้นอินเทอร์เฟซที่มีน้ำหนักสูงอาจเป็นอย่างนั้น คุณกำลังจมดิ่งอยู่ในตัวอย่างที่ฉันให้ไว้เพื่อชี้ให้เห็นว่าสิ่งที่ควรจะอยู่ด้วยกันคืออะไร
Pieter B

0

วัฒนธรรมเป็นที่โปรแกรมเมอร์ Java มักจะออกมาจากมหาวิทยาลัยที่มีการสอนหลักการ Object Orientated และหลักการออกแบบซอฟต์แวร์อย่างยั่งยืน

ในขณะที่ ErikE พูดอีกหลายคำในคำตอบของเขาคุณดูเหมือนจะไม่เขียนโค้ดที่ยั่งยืน สิ่งที่ฉันเห็นจากตัวอย่างของคุณคือมีความกังวลที่น่าสับสนอย่างมาก

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

แต่อย่างที่คุณบอกว่านี่ไม่ใช่ข้อเสีย: วันนี้มีการใช้ Java มานานกว่า 10 ปีฉันมักจะใช้ Node / Javascript หรือ Go สำหรับโครงการใหม่เพราะทั้งสองอนุญาตการพัฒนาที่รวดเร็วขึ้นและด้วยสถาปัตยกรรมสไตล์ไมโครบริการเหล่านี้ มักจะพอเพียง เมื่อพิจารณาจากข้อเท็จจริงที่ว่า Google เป็นคนแรกที่ใช้ Java เป็นอย่างมาก แต่เป็นผู้ที่เริ่มต้นจาก Go ฉันคิดว่าพวกเขาอาจทำแบบเดียวกัน แต่ถึงแม้ว่าตอนนี้ฉันจะใช้ Go และ Javascript ฉันยังคงใช้ทักษะการออกแบบมากมายที่ฉันได้รับจากการใช้งานมานานหลายปีและเข้าใจ Java


1
เครื่องมือการสรรหาบุคลากร foobar ที่ Google ใช้ช่วยให้สามารถใช้สองภาษาในการแก้ปัญหา: java และ python ฉันคิดว่ามันน่าสนใจที่ Go ไม่ใช่ตัวเลือก ฉันเกิดขึ้นกับงานนำเสนอนี้ใน Goและมีบางจุดที่น่าสนใจเกี่ยวกับ Java และ Python (รวมถึงภาษาอื่น ๆ ) ตัวอย่างเช่นมีสัญลักษณ์หนึ่งจุดที่โดดเด่น: "บางทีอาจเป็นเพราะโปรแกรมเมอร์ที่ไม่ใช่ผู้เชี่ยวชาญสับสน" ใช้ "พร้อมการตีความและการพิมพ์แบบไดนามิก" ควรค่าแก่การอ่าน
JimmyJames

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