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


23

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

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

Foo a = new Foo();
a.setProperty1("asdf");
a.setProperty2("bcde");

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

คุณจะตัดสินใจได้อย่างไรว่าประเภทวัตถุควรได้รับการออกแบบให้ไม่เปลี่ยนรูป? มีเกณฑ์ที่ดีในการตัดสินด้วยหรือไม่

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


1
โปรแกรมใน Erlang และแก้ไขปัญหาทั้งหมดแล้วทุกอย่างไม่เปลี่ยนรูปแบบ
Zachary K

1
@ ZacharyK ฉันคิดว่าจะพูดถึงบางอย่างเกี่ยวกับการเขียนโปรแกรมเชิงฟังก์ชั่น แต่ต้องงดเว้นเนื่องจากประสบการณ์ที่ จำกัด ของฉันกับภาษาการเขียนโปรแกรมที่ใช้งานได้
Ricket

คำตอบ:


27

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


11

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

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


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

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

4
@Doval: ไม่มีอะไรที่จะไม่เห็นด้วย 9000 ถูกต้องอย่างแน่นอน วัตถุที่ไม่เปลี่ยนรูปนั้นง่ายต่อการให้เหตุผล ส่วนหนึ่งคือสิ่งที่ทำให้มีประโยชน์สำหรับการเขียนโปรแกรมพร้อมกัน อีกส่วนคือคุณไม่ต้องกังวลเกี่ยวกับการเปลี่ยนแปลงของรัฐ การเพิ่มประสิทธิภาพก่อนวัยอันควรไม่เกี่ยวข้องที่นี่; การใช้วัตถุที่ไม่เปลี่ยนรูปนั้นเกี่ยวกับการออกแบบไม่ใช่ประสิทธิภาพและตัวเลือกที่ไม่ดีของโครงสร้างข้อมูลที่อยู่ด้านหน้าคือการมองในแง่ร้ายก่อนกำหนด
Robert Harvey

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

2
@Doval: ฉันอ่านโอกาซากิแล้ว โครงสร้างข้อมูลเหล่านั้นไม่ได้ใช้กันโดยทั่วไปเว้นแต่คุณจะใช้ภาษาที่รองรับกระบวนทัศน์การทำงานอย่างเต็มที่เช่น Haskell หรือ Lisp และฉันโต้แย้งความคิดที่ว่าโครงสร้างที่ไม่เปลี่ยนรูปนั้นเป็นตัวเลือกเริ่มต้น ระบบคอมพิวเตอร์ธุรกิจส่วนใหญ่ยังคงได้รับการออกแบบรอบโครงสร้างที่ไม่แน่นอน (เช่นฐานข้อมูลเชิงสัมพันธ์) การเริ่มต้นด้วยโครงสร้างข้อมูลที่เปลี่ยนแปลงไม่ได้เป็นความคิดที่ดี แต่ก็ยังเป็นหอคอยงาช้าง
Robert Harvey

6

มีสองวิธีที่สำคัญในการตัดสินใจว่าวัตถุนั้นไม่เปลี่ยนรูปหรือไม่

a) ขึ้นอยู่กับลักษณะของวัตถุ

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

b) ขึ้นอยู่กับทางเลือกการออกแบบปัจจัยภายนอก

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

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


4

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

การลดสถานะของโปรแกรมให้มีประโยชน์น้อยที่สุด

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

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


4

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

ไม่มีคำตอบง่ายๆ แต่สำหรับบางคนที่คุณต้องการทำให้วัตถุที่มีค่าขนาดเล็กไม่เปลี่ยนรูป Java ถูกต้องทำให้ Strings ไม่เปลี่ยนรูป แต่ทำไม่ถูกต้อง Date และ Calendar ไม่แน่นอน

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

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


เสียงมากเช่นวิธีการที่จะเลือกระหว่างสแต็คและกองเมื่อเขียน C หรือ C ++ :)
ricket

@Ricket: IMO ไม่มาก กองซ้อน / กองขึ้นอยู่กับอายุการใช้งานของวัตถุ มันเป็นเรื่องธรรมดามากใน C ++ ที่จะมีวัตถุที่ไม่แน่นอนในกองซ้อน
วินไคลน์

1

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

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

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

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

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


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

... และไม่มีสิ่งใดที่มีการสอบถาม "รหัสแฮช" ของมันใช้สำหรับล็อคหรือเข้าถึง " Objectคุณสมบัติที่ซ่อนอยู่" ของมันจากนั้นเปลี่ยนวัตถุโดยตรงจะไม่มีความแตกต่างจากการเขียนทับการอ้างอิงโดยอ้างอิงถึงวัตถุใหม่ซึ่งเป็นวัตถุ เหมือนกัน แต่สำหรับการเปลี่ยนแปลงที่ระบุ หนึ่งในจุดอ่อนเชิงความหมายที่ใหญ่ที่สุดใน Java, IMHO คือมันไม่มีวิธีการใดที่โค้ดสามารถระบุได้ว่าตัวแปรควรเป็นเพียงการอ้างอิงที่ไม่ใช่ชั่วคราวเท่านั้น การอ้างอิงควรจะพอเพียงกับวิธีการที่ไม่สามารถเก็บสำเนาได้หลังจากที่ส่งคืนแล้ว
supercat

0

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

เช่นนี้อาจมีราคาแพงมหาศาล:

/// @return A new mesh whose vertices have been transformed
/// by the specified transformation matrix.
Mesh transform(Mesh mesh, Matrix4f matrix);

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

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

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

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

/// @return The v1 * v2.
Vector3f vec_mul(Vector3f v1, Vector3f v2);

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


-1
Foo a = new Foo();
a.setProperty1("asdf");
a.setProperty2("bcde");

ถ้า Foo มีคุณสมบัติสองอย่างเท่านั้นมันเป็นเรื่องง่ายที่จะเขียนตัวสร้างที่ใช้สองข้อโต้แย้ง แต่สมมติว่าคุณเพิ่มคุณสมบัติอื่น จากนั้นคุณต้องเพิ่มตัวสร้างอื่น:

public Foo(String a, String b, SomethingElse c)

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


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

2
อย่างที่พูดกันมาหลายสิบปีแล้วสำหรับกรณีนี้"ถ้าคุณมีขั้นตอนที่มีพารามิเตอร์สิบตัวคุณอาจพลาดบางอย่าง"
9000

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

1
@Ricket: เพราะมันจะเพิ่มความเสี่ยงของการวางข้อโต้แย้งในการสั่งซื้อที่ไม่ถูกต้อง หากคุณใช้ตัวเซ็ตเตอร์หรือรูปแบบตัวสร้างนั่นก็ไม่น่าเป็นไปได้
Mike Baranczak

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