หากวัตถุที่ไม่เปลี่ยนรูปนั้นดีทำไมผู้คนยังคงสร้างวัตถุที่เปลี่ยนแปลงได้ [ปิด]


250

หากออบเจ็กต์ที่ไม่เปลี่ยนรูปแบบนั้นดีง่ายและให้ประโยชน์ในการเขียนโปรแกรมพร้อมกันเหตุใดโปรแกรมเมอร์จึงต้องสร้างออบเจ็กต์ที่เปลี่ยนแปลงไม่ได้²

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


¹ วัตถุที่ไม่เปลี่ยนรูปนั้นเป็นวัตถุที่ไม่สามารถแก้ไขสถานะได้หลังจากสร้างขึ้นแล้ว
² วัตถุที่ไม่แน่นอนเป็นวัตถุที่สามารถแก้ไขได้หลังจากที่มันถูกสร้างขึ้น


42
ฉันคิดว่านอกเหนือจากเหตุผลที่ชอบด้วยกฎหมาย (ดังที่กล่าวไว้โดยPéterด้านล่าง) "นักพัฒนาขี้เกียจ" เป็นเหตุผลที่พบได้บ่อยกว่านักพัฒนา "โง่" และก่อนหน้า "นักพัฒนาโง่" ก็มี "ผู้พัฒนาที่ไม่คุ้นเคย" ด้วย
Joachim Sauer

201
สำหรับนักเขียนโปรแกรมทุกคนที่เป็น evangelical / blogger จะมีผู้อ่านบล็อกตัวยงนับ 1,000 คนที่คิดค้นตัวเองใหม่ทันทีและนำเอาเทคนิคล่าสุดมาใช้ สำหรับทุกคนในนั้นมีโปรแกรมเมอร์กว่า 10,000 คนโดยมีจมูกของพวกเขาไปที่หินลับเพื่อให้ได้งานต่อวันและออกผลิตภัณฑ์ให้สำเร็จ พวกเหล่านั้นใช้เทคนิคที่ได้รับการทดลองและเชื่อถือได้ซึ่งใช้งานได้เป็นเวลาหลายปี พวกเขารอจนกว่าจะมีการนำเทคนิคใหม่ ๆ มาใช้อย่างกว้างขวางและแสดงผลประโยชน์ที่แท้จริงก่อนที่จะนำมาใช้ อย่าเรียกพวกเขาว่าโง่และพวกเขาก็ขี้เกียจเรียกพวกเขาว่า "ยุ่ง" แทน
ไบนารี Worrier

22
@ BinaryWorrier: วัตถุที่เปลี่ยนแปลงไม่ได้แทบจะเป็น "สิ่งใหม่" พวกเขาอาจไม่ได้ใช้อย่างหนักสำหรับวัตถุโดเมน แต่ Java และ C # มีพวกเขาตั้งแต่ต้น นอกจากนี้: "สันหลังยาว" ไม่ได้เป็นคำที่ไม่ดีเสมอไปบางประการ "ขี้เกียจ" เป็นข้อได้เปรียบอย่างแน่นอนสำหรับนักพัฒนาซอฟต์แวร์
Joachim Sauer

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

116
-1 วัตถุที่ไม่เปลี่ยนรูป arent 'ดี' มีความเหมาะสมไม่มากก็น้อยสำหรับสถานการณ์เฉพาะ ใครก็ตามที่บอกเทคนิคหนึ่งหรืออีกเทคนิคหนึ่งว่า "ดี" หรือ "ไม่ดี" อย่างเด็ดขาดสำหรับทุกสถานการณ์คือการขายศาสนาของคุณ
GrandmasterB

คำตอบ:


326

ทั้งวัตถุที่ไม่แน่นอนและไม่เปลี่ยนรูปมีการใช้ข้อดีและข้อเสียของตัวเอง

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

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

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

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


27
ถูกตัอง. โดยเฉพาะอย่างยิ่งในการเขียนโปรแกรม GUI วัตถุที่ไม่แน่นอนมีประโยชน์มาก
Florian Salihovic

23
ไม่ใช่แค่การต่อต้านฉันแน่ใจว่า devs จำนวนมากชอบที่จะลองใช้สิ่งล่าสุดและยิ่งใหญ่ที่สุด แต่บ่อยครั้งที่โครงการใหม่ ๆ เกิดขึ้นในสภาพแวดล้อมของนักพัฒนาซอฟต์แวร์โดยเฉลี่ยที่พวกเขาสามารถใช้แนวทางปฏิบัติใหม่เหล่านี้ได้? ไม่เคยมีใครสามารถหรือจะเขียนโครงการงานอดิเรกเพียงเพื่อลองรัฐไม่เปลี่ยนรูป
Steven Evers

29
คำเตือนเล็ก ๆ สองประการต่อไปนี้: (1) นำตัวละครเกมที่เคลื่อนไหว Pointชั้นใน NET สำหรับอินสแตนซ์จะไม่เปลี่ยนรูป แต่การสร้างจุดใหม่เป็นผลจากการเปลี่ยนแปลงเป็นเรื่องง่ายและราคาไม่แพงจึง การเคลื่อนไหวตัวละครที่ไม่เปลี่ยนรูปสามารถทำให้ถูกได้โดยการแยกส่วน“ ส่วนที่เคลื่อนไหว” ออก (แต่ใช่แล้วบางแง่มุมก็ไม่แน่นอน) (2)“ วัตถุที่มีขนาดใหญ่และ / หรือซับซ้อน” สามารถไม่เปลี่ยนรูปได้เป็นอย่างดี เงื่อนไขมักจะมีขนาดใหญ่และมักจะได้รับประโยชน์จากการเปลี่ยนแปลงไม่ได้ ฉันเคยเขียนคลาสกราฟที่ซับซ้อนซ้ำแล้วซ้ำอีกทำให้รหัสนั้นง่ายขึ้นและมีประสิทธิภาพยิ่งขึ้น ในกรณีเช่นนี้การมีตัวสร้างที่ไม่แน่นอนเป็นกุญแจสำคัญ
Konrad Rudolph

4
@ KonradRudolph, คะแนนดีขอบคุณ ฉันไม่ได้หมายความว่าจะออกกฎโดยใช้ความไม่สามารถเปลี่ยนแปลงได้ในวัตถุที่ซับซ้อน แต่การนำคลาสดังกล่าวไปใช้อย่างถูกต้องและมีประสิทธิภาพนั้นยังห่างไกลจากงานที่ไม่สำคัญและความพยายามพิเศษที่จำเป็นอาจไม่ถูกต้องเสมอไป
PéterTörök

6
คุณสร้างจุดที่ดีเกี่ยวกับสถานะตัวตน นี่คือเหตุผลว่าทำไม Rich Hickey (ผู้เขียน Clojure) จึงแยกทั้งสองออกจากกันใน Clojure อาจมีใครโต้แย้งได้ว่ารถที่คุณมีด้วยน้ำมัน 1/2 ถังไม่ใช่รถคันเดียวกับที่มีน้ำมัน 1/4 ถัง พวกมันมีเอกลักษณ์เหมือนกัน แต่พวกมันไม่เหมือนกันทุกครั้งที่ "ติ๊ก" ในความเป็นจริงของเราสร้างโคลนของวัตถุทุกอย่างในโลกของเราสมองของเราก็จะต่อสิ่งเหล่านี้เข้าด้วยกัน Clojure มีผู้อ้างอิงอะตอมตัวแทน ฯลฯ เพื่อแสดงเวลา และแผนที่เวกเตอร์และรายการตามเวลาจริง
Timothy Baldridge

130

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


9
ใน IDEs ที่ทันสมัยส่วนใหญ่ฉันรู้ว่ามันต้องใช้ความพยายามในการสร้าง getters เพียงเท่านี้เพื่อสร้างทั้ง getters และ setters แม้ว่ามันจะเป็นความจริงที่การเพิ่มfinal, constฯลฯ ใช้เวลาบิตของความพิเศษ ... ถ้าคุณตั้งค่า :-) แม่แบบรหัส
PéterTörök

10
@ PéterTörökมันไม่ใช่แค่ความพยายามเพิ่มเติม - มันเป็นความจริงที่ว่า coders เพื่อนของคุณจะต้องการที่จะแขวนคุณในรูปแบบเพราะพวกเขาพบว่ารูปแบบการเข้ารหัสของคุณดังนั้นคนต่างด้าวกับประสบการณ์ของพวกเขา สิ่งนี้ทำให้หมดกำลังใจเช่นกัน
Onorio Catenacci

5
นั่นอาจจะเอาชนะได้ด้วยการสื่อสารและการศึกษาที่มากขึ้นเช่นแนะนำให้พูดคุยหรือนำเสนอให้เพื่อนร่วมทีมเกี่ยวกับรูปแบบการเข้ารหัสใหม่ก่อนที่จะนำมันมาใช้จริงใน codebase ที่มีอยู่ มันเป็นความจริงที่โครงการที่ดีมีรูปแบบการเข้ารหัสทั่วไปซึ่งไม่ได้เป็นเพียงการรวมกันของรูปแบบการเข้ารหัสที่สมาชิกโครงการทุกคน (อดีตและปัจจุบัน) ชื่นชอบ ดังนั้นการแนะนำหรือเปลี่ยนสำนวนการเข้ารหัสควรเป็นการตัดสินใจของทีม
PéterTörök

3
@ PéterTörökในวัตถุที่ไม่แน่นอนภาษาที่เปลี่ยนแปลงได้เป็นพฤติกรรมเริ่มต้น หากคุณต้องการเฉพาะวัตถุที่ไม่เปลี่ยนรูปได้ดีที่สุดคือเปลี่ยนเป็นภาษาที่ใช้งานได้
emory

3
@ PéterTörökมันไร้เดียงสานิดหน่อยที่จะคิดว่าการรวมความไม่เปลี่ยนแปลงเข้ากับโปรแกรมไม่ได้เกี่ยวข้องอะไรมากไปกว่าการทิ้งเซ็ตเตอร์ทั้งหมด คุณยังคงต้องการวิธีสำหรับสถานะของโปรแกรมในการเปลี่ยนแบบเพิ่มขึ้นและสำหรับสิ่งนี้คุณต้องการผู้สร้างหรือการเปลี่ยนแปลงแบบไอติมหรือพร็อกซีที่ไม่แน่นอนหรือไม่แน่นอนซึ่งทั้งหมดใช้เวลาประมาณ 1 พันล้านเท่าของความพยายาม
ซาด Saeeduddin

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

  2. นักพัฒนาส่วนใหญ่ไม่ได้ทำสิ่งใดที่ความต้องการด้านประสิทธิภาพมีความสำคัญมากพอที่พวกเขาจะต้องมุ่งเน้นไปที่การทำงานพร้อมกัน (หรือปัญหาอื่น ๆ

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

        public class ImmutablePerson { 
    
         public ImmutablePerson(string name, ImmutableEventList eventsToAttend)
         {
              this.name = name;
              this.eventsToAttend = eventsToAttend;
         }
         private string name;
         private ImmutableEventList eventsToAttend;
    
         public string Name { get { return this.name; } }
    
         public ImmutablePerson RSVP(ImmutableEvent immutableEvent){
             // the person is RSVPing an event, thus mutating the state 
             // of the eventsToAttend.  so we need a new person with a reference
             // to the new Event
             ImmutableEvent newEvent = immutableEvent.OnRSVPReceived(this);
             ImmutableEventList newEvents = this.eventsToAttend.Add(newEvent));
             var newSelf = new ImmutablePerson(name, newEvents);
             return newSelf;
         }
        }
    
        public class ImmutableEvent { 
         public ImmutableEvent(DateTime when, ImmutablePersonList peopleAttending, ImmutablePersonList peopleNotAttending){
             this.when = when;     
             this.peopleAttending = peopleAttending;
             this.peopleNotAttending = peopleNotAttending;
         }
         private DateTime when; 
         private ImmutablePersonList peopleAttending;
         private ImmutablePersonList peopleNotAttending;
         public ImmutableEvent OnReschedule(DateTime when){
               return new ImmutableEvent(when,peopleAttending,peopleNotAttending);
         }
         //  notice that this will be an infinite loop, because everytime one counterpart
         //  of the bidirectional relationship is added, its containing object changes
         //  meaning it must re construct a different version of itself to 
         //  represent the mutated state, the other one must update its
         //  reference thereby obsoleting the reference of the first object to it, and 
         //  necessitating recursion
         public ImmutableEvent OnRSVPReceived(ImmutablePerson immutablePerson){
               if(this.peopleAttending.Contains(immutablePerson)) return this;
               ImmutablePersonList attending = this.peopleAttending.Add(immutablePerson);
               ImmutablePersonList notAttending = this.peopleNotAttending.Contains( immutablePerson ) 
                                    ? peopleNotAttending.Remove(immutablePerson)
                                    : peopleNotAttending;
               return new ImmutableEvent(when, attending, notAttending);
         }
        }
        public class ImmutablePersonList
        {
          private ImmutablePerson[] immutablePeople;
          public ImmutablePersonList(ImmutablePerson[] immutablePeople){
              this.immutablePeople = immutablePeople;
          }
          public ImmutablePersonList Add(ImmutablePerson newPerson){
              if(this.Contains(newPerson)) return this;
              ImmutablePerson[] newPeople = new ImmutablePerson[immutablePeople.Length];
              for(var i=0;i<immutablePeople.Length;i++)
                  newPeople[i] = this.immutablePeople[i];
              newPeople[immutablePeople.Length] = newPerson;
          }
          public ImmutablePersonList Remove(ImmutablePerson newPerson){
              if(immutablePeople.IndexOf(newPerson) != -1)
              ImmutablePerson[] newPeople = new ImmutablePerson[immutablePeople.Length-2];
              bool hasPassedRemoval = false;
              for(var i=0;i<immutablePeople.Length;i++)
              {
                 hasPassedRemoval = hasPassedRemoval || immutablePeople[i] == newPerson;
                 newPeople[i] = this.immutablePeople[hasPassedRemoval ? i + 1 : i];
              }
              return new ImmutablePersonList(newPeople);
          }
          public bool Contains(ImmutablePerson immutablePerson){ 
             return this.immutablePeople.IndexOf(immutablePerson) != -1;
          } 
        }
        public class ImmutableEventList
        {
          private ImmutableEvent[] immutableEvents;
          public ImmutableEventList(ImmutableEvent[] immutableEvents){
              this.immutableEvents = immutableEvents;
          }
          public ImmutableEventList Add(ImmutableEvent newEvent){
              if(this.Contains(newEvent)) return this;
              ImmutableEvent[] newEvents= new ImmutableEvent[immutableEvents.Length];
              for(var i=0;i<immutableEvents.Length;i++)
                  newEvents[i] = this.immutableEvents[i];
              newEvents[immutableEvents.Length] = newEvent;
          }
          public ImmutableEventList Remove(ImmutableEvent newEvent){
              if(immutableEvents.IndexOf(newEvent) != -1)
              ImmutableEvent[] newEvents = new ImmutableEvent[immutableEvents.Length-2];
              bool hasPassedRemoval = false;
              for(var i=0;i<immutablePeople.Length;i++)
              {
                 hasPassedRemoval = hasPassedRemoval || immutableEvents[i] == newEvent;
                 newEvents[i] = this.immutableEvents[hasPassedRemoval ? i + 1 : i];
              }
              return new ImmutableEventList(newPeople);
          }
          public bool Contains(ImmutableEvent immutableEvent){ 
             return this.immutableEvent.IndexOf(immutableEvent) != -1;
          } 
        }
    

2
@AndresF. หากคุณมีวิธีการที่แตกต่างกันในการรักษากราฟที่ซับซ้อนที่มีความสัมพันธ์แบบสองทิศทางโดยใช้วัตถุที่ไม่เปลี่ยนรูปแบบเท่านั้นฉันจะชอบที่จะได้ยิน (ผมถือว่าเราสามารถยอมรับว่าคอลเลกชัน / อาร์เรย์เป็นวัตถุ)
smartcaveman

2
@AndresF., (1) คำสั่งแรกของฉันไม่เป็นสากลดังนั้นจึงไม่ใช่เท็จ ฉันให้รหัสตัวอย่างเพื่ออธิบายว่ามันจำเป็นจริงหรือไม่ในบางกรณีซึ่งเกิดขึ้นบ่อยมากในการพัฒนาแอปพลิเคชัน (2) ความสัมพันธ์แบบสองทิศทางต้องการความไม่แน่นอนโดยทั่วไป ฉันไม่เชื่อว่า Java เป็นตัวการ ดังที่ฉันพูดฉันมีความสุขที่จะประเมินทางเลือกที่สร้างสรรค์ใด ๆ ที่คุณจะแนะนำ แต่ ณ จุดนี้คุณมีความคิดเห็นที่ฟังดูเหมือน "คุณผิดเพราะฉันพูดอย่างนั้น"
smartcaveman

14
@ smartcaveman เกี่ยวกับ (2) ฉันยังไม่เห็นด้วย: โดยทั่วไปแล้ว "ความสัมพันธ์แบบสองทิศทาง" เป็นแนวคิดทางคณิตศาสตร์มุมฉากกับความไม่แน่นอน ตามปกติแล้วจะนำไปใช้ใน Java มันต้องการความไม่แน่นอน (ฉันเห็นด้วยกับคุณในจุดนั้น) แต่ผมอาจจะคิดว่าการดำเนินการทางเลือก: ชั้นความสัมพันธ์ระหว่างวัตถุทั้งสองมีนวกรรมิกRelationship(a, b); ณ จุดของการสร้างความสัมพันธ์ทั้งเอนทิตีaและbมีอยู่แล้วและความสัมพันธ์นั้นก็ไม่เปลี่ยนแปลง ฉันไม่ได้บอกว่าวิธีนี้มีประโยชน์ใน Java; แค่ว่ามันเป็นไปได้
Andres F.

4
@AndresF. ดังนั้นขึ้นอยู่กับสิ่งที่คุณกำลังจะบอกว่าถ้าRเป็นRelationship(a,b)และทั้งสองaและbจะไม่เปลี่ยนรูป, ค่าaมิได้จะถือการอ้างอิงถึงb Rเพื่อให้สามารถใช้งานได้การอ้างอิงจะต้องถูกเก็บไว้ที่อื่น (เช่นคลาสคงที่) ฉันเข้าใจความตั้งใจของคุณถูกต้องหรือไม่?
smartcaveman

9
มันเป็นไปได้ที่จะเก็บความสัมพันธ์แบบสองทิศทางสำหรับข้อมูลที่ไม่เปลี่ยนรูปเมื่อ Chthulhu ชี้ให้เห็นผ่านความเกียจคร้าน นี่เป็นวิธีหนึ่งในการทำสิ่งนี้: haskell.org/haskellwiki/Tying_the_Knot
Thomas Eding

36

ฉันได้อ่าน "โครงสร้างข้อมูลที่สามารถใช้งานได้อย่างหมดจด" และทำให้ฉันรู้ว่ามีโครงสร้างข้อมูลบางอย่างที่ใช้งานได้ง่ายขึ้นโดยใช้วัตถุที่ไม่แน่นอน

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

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


3
นี่เป็นหนังสือโอกาซากิหรือไม่
หอยทากเครื่องกล

อ๋อ ค่อนข้างจะแห้ง แต่เป็นข้อมูลที่ดีมากมาย ...
พอล Sanwald

4
ตลกฉันคิดเสมอว่าต้นไม้สีแดง / ดำของ Okasakis ง่ายกว่ามาก 10 บรรทัดขึ้นไป ฉันเดาว่าข้อดีที่สุดคือเมื่อคุณต้องการเก็บเวอร์ชันเก่าไว้ด้วย
โทมัส Ahle

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

29

จากมุมมองของฉันนั่นคือการขาดความตระหนัก หากคุณดูภาษา JVM อื่น ๆ ที่รู้จัก (Scala, Clojure) วัตถุที่เปลี่ยนแปลงได้จะเห็นได้ยากในรหัสและนั่นคือสาเหตุที่ผู้คนเริ่มใช้งานพวกเขาในสถานการณ์ที่เธรดเดียวไม่เพียงพอ

ขณะนี้ฉันเรียนรู้ Clojure และมีประสบการณ์เล็กน้อยใน Scala (4 ปีขึ้นไปใน Java ด้วย) และรูปแบบการเขียนโค้ดของคุณเปลี่ยนไปเนื่องจากการรับรู้ของรัฐ


บางที "รู้จัก" มากกว่า "ยอดนิยม" อาจเป็นทางเลือกที่ดีกว่าของคำ
Den

ถูกต้องเลย.
Florian Salihovic

5
+1: ฉันเห็นด้วย: หลังจากเรียนรู้ Scala และ Haskell แล้วฉันมักจะใช้ขั้นสุดท้ายใน Java และ const ใน C ++ ทุกที่ ฉันยังใช้วัตถุที่ไม่เปลี่ยนรูปถ้าเป็นไปได้และในขณะที่วัตถุที่ไม่แน่นอนยังคงต้องการบ่อยครั้งมันวิเศษมากที่คุณสามารถใช้วัตถุที่ไม่เปลี่ยนรูปได้
Giorgio

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

13

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


4
+1, รูปแบบ getter / setter ถูกใช้บ่อยเกินไปเนื่องจากการใช้งานบางประเภทหลังจากการวิเคราะห์ข้อมูลครั้งแรก
Jaap

นี่อาจเป็นประเด็นใหญ่ ... "เพราะนั่นเป็นวิธีที่คนอื่นทำ" ... ดังนั้นจึงต้องถูกต้อง สำหรับโปรแกรม "Hello World" อาจเป็นวิธีที่ง่ายที่สุด การจัดการการเปลี่ยนแปลงสถานะของออบเจ็กต์ด้วยคุณสมบัติที่เปลี่ยนแปลงไม่ได้ ... ซึ่งมีความยุ่งยากมากกว่าความเข้าใจ "Hello World" เล็กน้อย 20 ปีต่อมาฉันประหลาดใจอย่างมากที่จุดสุดยอดของการเขียนโปรแกรมศตวรรษที่ 20 คือการเขียนวิธี getX และ setX (น่าเบื่อมาก) ทุก ๆ คุณลักษณะของวัตถุที่ไม่มีโครงสร้างใด ๆ เพียงหนึ่งก้าวจากการเข้าถึงคุณสมบัติสาธารณะโดยตรงด้วยความไม่แน่นอน 100%
Darrell Teague

12

ระบบ Java ขององค์กรทุกระบบที่ฉันทำงานมาในอาชีพของฉันนั้นใช้ Hibernate หรือ Java Persistence API (JPA) Hibernate และ JPA บอกว่าระบบของคุณใช้วัตถุที่ไม่แน่นอนเนื่องจากสถานที่ทั้งหมดของพวกเขาคือพวกเขาตรวจจับและบันทึกการเปลี่ยนแปลงวัตถุข้อมูลของคุณ สำหรับหลายโครงการความง่ายในการพัฒนาที่ Hibernate นำมานั้นน่าสนใจมากกว่าประโยชน์ของวัตถุที่ไม่เปลี่ยนรูป

เห็นได้ชัดว่าวัตถุที่เปลี่ยนแปลงไม่ได้นั้นมีความยาวกว่า Hibernate มากดังนั้น Hibernate อาจไม่ใช่ 'ต้นกำเนิด' ดั้งเดิมของความนิยมของวัตถุที่ไม่แน่นอน บางทีความนิยมของวัตถุที่ไม่แน่นอนทำให้ไฮเบอร์เนตสามารถเติบโตได้

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


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

9

จุดสำคัญที่ยังไม่ได้กล่าวถึงคือการมีสถานะของวัตถุที่ไม่แน่นอนทำให้มันเป็นไปได้ที่จะมีตัวตนของวัตถุที่ encapsulate รัฐนั้นจะไม่เปลี่ยนรูป

หลายโปรแกรมได้รับการออกแบบมาเพื่อจำลองสิ่งต่าง ๆ ในโลกแห่งความเป็นจริง สมมติว่าเวลา 12:51 น. ตัวแปรบางตัวAllTrucksมีการอ้างอิงถึง object # 451 ซึ่งเป็นรากของโครงสร้างข้อมูลซึ่งระบุว่ามีสินค้าใดบ้างในรถบรรทุกทั้งหมดของกองทัพเรือในเวลานั้น (12:51 น.) และตัวแปรบางอย่างBobsTruckสามารถใช้เพื่อรับการอ้างอิงถึงวัตถุ # 24601 คะแนนไปยังวัตถุซึ่งระบุว่ามีสินค้าใดบ้างที่บรรทุกอยู่ในรถบรรทุกของ Bob ในเวลานั้น (12:51 น.) เมื่อเวลา 12:52 น. รถบรรทุกบางส่วน (รวมถึงของ Bob) จะถูกโหลดและไม่โหลดและโครงสร้างข้อมูลจะได้รับการอัปเดตดังนั้นAllTrucksตอนนี้จะมีการอ้างอิงไปยังโครงสร้างข้อมูลซึ่งบ่งชี้ว่าสินค้าอยู่ในรถบรรทุกทั้งหมดตั้งแต่ 12:52 น

จะเกิดอะไรขึ้นBobsTruck?

หากคุณสมบัติ 'บรรทุกสินค้า' ของวัตถุรถบรรทุกแต่ละชิ้นไม่เปลี่ยนรูปแบบแล้ววัตถุ # 24601 จะเป็นตัวแทนของรัฐที่รถบรรทุกของ Bob มีเวลา 12:51 น. หากBobsTruckมีการอ้างอิงโดยตรงไปยัง object # 24601 ดังนั้นหากรหัสที่มีการอัปเดตAllTrucksเกิดขึ้นเพื่ออัปเดตBobsTruckก็จะยุติการแสดงสถานะปัจจุบันของรถบรรทุกของ Bob โปรดทราบว่านอกจากBobsTruckจะถูกเก็บไว้ในวัตถุที่ไม่แน่นอนบางรูปแบบวิธีเดียวที่รหัสซึ่งการอัปเดตAllTrucksสามารถอัปเดตจะเป็นถ้ารหัสนั้นได้รับการโปรแกรมอย่างชัดเจน

หากต้องการใช้BobsTruckเพื่อสังเกตสถานะรถบรรทุกของ Bob ในขณะที่ยังคงรักษาวัตถุทั้งหมดที่ไม่เปลี่ยนรูปหนึ่งอาจมีBobsTruckฟังก์ชั่นที่ไม่เปลี่ยนรูปซึ่งเมื่อได้รับค่าที่AllTrucksมีหรือ ณ เวลาใดก็ตามจะให้สถานะของรถบรรทุกของ Bob ที่ เวลานั้น. เราสามารถมีฟังก์ชั่นที่ไม่เปลี่ยนรูปแบบได้ซึ่งหนึ่งในนั้นจะเป็นข้างต้นและอีกอันหนึ่งจะยอมรับการอ้างอิงไปยังสถานะของกองทัพเรือและรัฐรถบรรทุกใหม่และกลับไปอ้างอิงถึงสถานะของกองทัพเรือใหม่ที่ จับคู่กับรถเก่ายกเว้นรถบรรทุกของ Bob จะมีสถานะใหม่

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

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

หากวัตถุรถบรรทุกแต่ละชิ้นไม่แน่นอน แต่มีตัวตนที่ไม่เปลี่ยนรูปแบบสถานการณ์แบบมัลติเธรดจะสะอาดขึ้น อาจอนุญาตให้ใช้เธรดเดียวเท่านั้นในแต่ละครั้งบนรถบรรทุกใดก็ตาม แต่เธรดที่ทำงานบนรถบรรทุกที่แตกต่างกันสามารถทำได้โดยไม่มีการรบกวน ในขณะที่มีวิธีการหนึ่งที่สามารถเลียนแบบพฤติกรรมดังกล่าวแม้ว่าจะใช้วัตถุที่ไม่เปลี่ยนรูป (เช่นสามารถกำหนดวัตถุ "AllTrucks" เพื่อให้การตั้งค่าสถานะของรถบรรทุกที่เป็นของ XXX เป็น SSS นั้นจะต้องสร้างวัตถุที่กล่าวว่า "เป็น [เวลา] สถานะของรถบรรทุกที่เป็นของ [XXX] คือตอนนี้ [SSS] สถานะของทุกสิ่งอื่นคือ [ค่าเก่าของ AllTrucks] "การสร้างวัตถุเช่นนี้จะเร็วพอที่แม้จะมีการโต้แย้งก็ตามCompareExchangeวงจะใช้เวลาไม่นาน ในทางกลับกันการใช้โครงสร้างข้อมูลดังกล่าวจะช่วยเพิ่มระยะเวลาในการค้นหารถบรรทุกของบุคคลโดยเฉพาะอย่างยิ่ง การใช้วัตถุที่ไม่แน่นอนที่มีตัวตนที่ไม่เปลี่ยนรูปได้จะช่วยหลีกเลี่ยงปัญหานั้นได้


8

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

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


7

ตรวจสอบการโพสต์บล็อกนี้: http://www.yegor256.com/2014/06/09/objects-should-be-immutable.html มันสรุปว่าทำไมวัตถุที่ไม่เปลี่ยนรูปนั้นดีกว่าไม่แน่นอน นี่คือรายการสั้น ๆ ของการขัดแย้ง:

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

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


5

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

มีสี่ปัญหาเกี่ยวกับเรื่องนี้ส่วนใหญ่เกี่ยวข้องกับการผูกข้อมูล :

  1. Java Constructors สะท้อน meta-data ไม่ได้เก็บชื่ออาร์กิวเมนต์
  2. Java Constructors (และเมธอด) ไม่มีพารามิเตอร์ชื่อ (หรือที่เรียกว่าเลเบล) ทำให้เกิดความสับสนกับพารามิเตอร์จำนวนมาก
  3. เมื่อสืบทอดวัตถุที่ไม่เปลี่ยนรูปอื่น ๆ ลำดับที่เหมาะสมของตัวสร้างจะต้องถูกเรียก นี่อาจเป็นเรื่องยากที่จะยอมแพ้และปล่อยให้หนึ่งในทุ่งที่ไม่ใช่รอบชิงชนะเลิศ
  4. เทคโนโลยีที่มีผลผูกพันส่วนใหญ่ (เช่นการเชื่อมโยงกับข้อมูลสปริง MVC, ไฮเบอร์เนต ฯลฯ ... ) จะทำงานกับตัวสร้างเริ่มต้นที่ไม่มีอาร์กิวเมนต์ (นี่เป็นเพราะคำอธิบายประกอบไม่ได้มีอยู่เสมอ)

คุณสามารถลด # 1 และ # 2 โดยใช้คำอธิบายประกอบเช่น@ConstructorPropertiesและการสร้างวัตถุตัวสร้างที่ไม่แน่นอนอื่น ๆ (โดยปกติจะคล่องแคล่ว) เพื่อสร้างวัตถุที่ไม่เปลี่ยนรูป


5

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

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

มันไม่ใหญ่เท่าที่ควรเพราะมันยากไม่สามารถใช้ได้กับทุกภาษาและคนส่วนใหญ่ได้รับการสอนการเขียนโค้ดที่จำเป็น

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

ยังจำได้ว่าสถานะของโปรแกรมเมอร์ส่วนใหญ่ไม่ดี การเขียนโปรแกรมส่วนใหญ่ที่ทำในป่านั้นน่ากลัวและเกิดจากการขาดความเข้าใจและการเมือง


4

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


4

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

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


1

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

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

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

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

ในฐานะที่เป็น PS ฉันรู้สึกว่า Java getters และ setters กำลังจะออกไปจากมือ ตรวจสอบนี้ออก


7
รัฐที่ไม่เปลี่ยนรูปนั้นยังคงเป็นของรัฐ
Jeremy Heiler

3
@JeremyHeiler: ทรู แต่มันเป็นสถานะของสิ่งที่เป็นไม่แน่นอน หากไม่มีสิ่งใดกลายพันธุ์มีเพียงรัฐเดียวเท่านั้นซึ่งเป็นสิ่งเดียวกับที่ไม่มีรัฐเลย
RalphChapin

1

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

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

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

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

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


1

วัตถุที่ไม่แน่นอนถูกนำมาใช้เมื่อคุณต้องตั้งค่าหลายรายการหลังจากอินสแตนซ์วัตถุ

คุณไม่ควรมีคอนสตรัคเตอร์ด้วยพูดหกพารามิเตอร์ แต่คุณปรับเปลี่ยนวัตถุด้วยวิธีการตั้งค่า

ตัวอย่างนี้เป็นวัตถุรายงานที่มีตัวตั้งค่าสำหรับแบบอักษรการวางแนว ฯลฯ

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

แก้ไข: รูปแบบตัวสร้างสามารถใช้สร้างสถานะทั้งหมดของวัตถุ


3
สิ่งนี้จะถูกนำเสนอราวกับว่าความไม่แน่นอนและการเปลี่ยนแปลงหลังจากการสร้างอินสแตนซ์เป็นวิธีเดียวในการตั้งค่าหลายค่า เพื่อให้ทราบถึงความครบถ้วนว่ารูปแบบของตัวสร้างนั้นมีความสามารถที่เท่าเทียมกันหรือมีประสิทธิภาพมากกว่าและไม่ต้องการการเสียสละที่ไม่สามารถเปลี่ยนแปลงได้ new ReportBuilder().font("Arial").orientation("landscape").build()
ริ้น

1
"การใช้ลายเซ็นตัวสร้างที่มีความยาวมากนั้นเป็นประโยชน์ไม่ได้": คุณสามารถจัดกลุ่มพารามิเตอร์เป็นวัตถุขนาดเล็กและส่งผ่านวัตถุเหล่านี้เป็นพารามิเตอร์ไปยังตัวสร้างได้
Giorgio

1
@cHao จะทำอย่างไรถ้าคุณต้องการตั้งค่าแอตทริบิวต์ 10 หรือ 15 นอกจากนี้ก็ดูเหมือนจะไม่ดีที่วิธีการตั้งชื่อส่งกลับwithFont Report
Tulains Córdova

1
เท่าที่การตั้งค่าคุณลักษณะ 10 หรือ 15 รหัสที่จะทำเช่นนั้นจะไม่น่าแปลกใจถ้า (1) Java รู้วิธีตัดการสร้างวัตถุกลางเหล่านั้นทั้งหมดและถ้า (2) อีกครั้งชื่อจะได้มาตรฐาน มันไม่ใช่ปัญหากับการเปลี่ยนไม่ได้ มันเป็นปัญหากับ Java ที่ไม่รู้วิธีการทำได้ดี
cHao

1
@cHao การสร้างสายโซ่สำหรับแอตทริบิวต์ 20 นั้นน่าเกลียด รหัสน่าเกลียดมีแนวโน้มว่าจะเป็นรหัสคุณภาพต่ำ
Tulains Córdova

1

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

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

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

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

ดังนั้นทำไมโปรแกรมเมอร์หลายคนถึงใช้วัตถุที่ไม่แน่นอน IMHO ด้วยเหตุผลสองประการ:

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

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

1
ฉันไม่ใช่ผู้เชี่ยวชาญ FP แต่การสื่อสารแบบเธรด AFAIK (1) สามารถทำได้โดยการสร้างค่าที่ไม่เปลี่ยนรูปแบบในหนึ่งเธรดและอ่านในอีกหัวข้อหนึ่ง (อีกครั้ง AFAIK นี่คือแนวทางแบบ Erlang) (2) AFAIK สัญลักษณ์สำหรับการตั้งค่าคุณสมบัติ ไม่เปลี่ยนแปลงมากนัก (เช่นใน Haskell setProperty ค่าบันทึกสอดคล้องกับ Java record.setProperty (ค่า)) เฉพาะการเปลี่ยนแปลงความหมายเพราะผลของการตั้งค่าคุณสมบัติเป็นบันทึกไม่เปลี่ยนรูปใหม่
จอร์โจ

1
"ทั้งคู่จะต้องมีการอ้างอิงไปยังวัตถุที่ใช้ร่วมกันซึ่งหนึ่งสามารถใส่ข้อมูลและอื่น ๆ สามารถอ่านได้": แม่นยำยิ่งขึ้นคุณสามารถทำให้วัตถุไม่เปลี่ยนรูป (สมาชิกทั้งหมด const ใน C ++ หรือขั้นสุดท้ายใน Java) และตั้งเนื้อหาทั้งหมดใน นวกรรมิก จากนั้นวัตถุที่ไม่เปลี่ยนรูปนี้จะถูกส่งมอบจากเธรดผู้ผลิตไปยังเธรดผู้บริโภค
จอร์โจ

1
(2) ฉันได้แสดงประสิทธิภาพไว้แล้วเนื่องจากไม่ใช้สถานะไม่เปลี่ยนรูป แน่นอนเกี่ยวกับ (1) กลไกที่ใช้การสื่อสารระหว่างเธรดต้องการสถานะที่ไม่แน่นอน แต่คุณสามารถซ่อนสิ่งนี้จากโมเดลการเขียนโปรแกรมของคุณดูตัวอย่างโมเดลนักแสดง ( en.wikipedia.org/wiki/Actor_model ) ดังนั้นแม้ว่าในระดับที่ต่ำกว่าคุณต้องมีความไม่แน่นอนในการใช้การสื่อสารคุณสามารถมีระดับนามธรรมที่คุณสื่อสารระหว่างเธรดที่ส่งวัตถุที่ไม่เปลี่ยนรูปแบบไปมา
จอร์โจ

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

1

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

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

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


1

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

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

case class Person(id: String, firstName: String, lastName: String)

val joe = Person("123", "Joe", "Doe")
val spouse = Person(id = "124", firstName = "Mary", lastName = "Moe")
val joeMarried = joe.copy(lastName = "Doe-Moe")

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


นี้ดูเหมือนจะไม่เพิ่มอะไรที่สำคัญกว่าจุดทำและอธิบายในก่อน 24 คำตอบ
ริ้น

@gnat คำตอบก่อนหน้าใดที่ทำให้ประเด็นที่ว่าภาษากระแสหลักส่วนใหญ่ไม่สนับสนุนการเปลี่ยนแปลงไม่ได้อย่างเหมาะสม? ฉันคิดว่าจุดนั้นไม่ได้ถูกสร้างขึ้นมา (ฉันตรวจสอบแล้ว) แต่นี่เป็นอุปสรรคสำคัญสำหรับ IMHO
Hans-Peter Störr

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

0

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

ผู้คนจำนวนมากคิดว่าตัวแปรดั้งเดิมและตัวแปรวัตถุที่มีตัวดัดแปลงสุดท้ายที่อยู่ข้างหน้านั้นไม่เปลี่ยนรูป แต่สิ่งนี้ไม่เป็นความจริง ดังนั้นสุดท้ายก็ไม่ได้หมายความว่าตัวแปรจะเปลี่ยนแปลงไม่ได้ ลองดูตัวอย่างโค้ดที่ลิงค์นี้ :

public abstract class FinalBase {

    private final int variable; // Unset

    /* if final really means immutable than
     * I shouldn't be able to set the variable
     * but I can.
     */
    public FinalBase(int variable) { 
        this.variable = variable;
    }

    public int getVariable() {
        return variable;
    }

    public abstract void method();
}

// This is not fully necessary for this example
// but helps you see how to set the final value 
// in a sub class.
public class FinalSubclass extends FinalBase {

    public FinalSubclass(int variable) {
        super(variable);
    }

    @Override
    public void method() {
        System.out.println( getVariable() );
    }

    @Override
    public int getVariable() {

        return super.getVariable();
    }

    public static void main(String[] args) {
        FinalSubclass subclass = new FinalSubclass(10);
        subclass.method();
    }
}

-1

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


1
ฉันไม่สามารถหาเลยที่ผมได้อ่านบทความนี้เกี่ยวกับต้นกำเนิดของ OOP แต่ตามวิกิพีเดียบางระบบสารสนเทศแบบบูรณาการในภูมิภาคของ บริษัท จัดส่งสินค้าคอนเทนเนอร์ขนาดใหญ่OOCLถูกเขียนในสมอลล์ทอล์ค
Alexey

-2

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


5
finalจริง ๆ แล้วประมาณ 1/4 ของขั้นตอนสู่การไม่เปลี่ยนรูป ไม่เห็นว่าทำไมคุณพูดถึงมัน
cHao

คุณอ่านโพสต์ของฉันจริงหรือ
Ralf H

คุณอ่านคำถามจริงหรือ :) มันไม่มีอะไรเกี่ยวข้องfinalเลย การนำมันมาใช้ในบริบทนี้ก่อให้เกิดการรวมตัวที่แปลกประหลาดของfinal"ไม่แน่นอน" เมื่อจุดสำคัญfinalคือการป้องกันการกลายพันธุ์บางประเภท (BTW ไม่ใช่ downvote ของฉัน.)
cHao

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

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