อะไรคือข้อเสียของประเภทที่ไม่เปลี่ยนรูป?


12

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

ในเวลาเดียวกันฉันไม่ค่อยเห็นประเภทที่ไม่เปลี่ยนรูปในแอปพลิเคชั่นอื่น ๆ แม้ว่าความไม่แน่นอนจะไม่เกิดประโยชน์ก็ตาม

คำถาม:ทำไมประเภทที่ไม่เปลี่ยนรูปแบบจึงไม่ค่อยถูกใช้ในแอปพลิเคชันอื่น

  • เป็นเพราะมันนานกว่าที่จะเขียนโค้ดสำหรับประเภทที่ไม่เปลี่ยนรูป
  • หรือฉันกำลังพลาดบางสิ่งบางอย่างและมีข้อบกพร่องที่สำคัญเมื่อใช้ประเภทที่ไม่เปลี่ยนรูปแบบ?

ตัวอย่างจากชีวิตจริง

สมมติว่าคุณได้รับWeatherRESTful API เช่นนั้น:

public Weather FindWeather(string city)
{
    // TODO: Load the JSON response from the RESTful API and translate it into an instance
    // of the Weather class.
}

สิ่งที่เราจะเห็นโดยทั่วไปคือ (บรรทัดใหม่และความคิดเห็นถูกลบออกเพื่อย่อรหัส):

public sealed class Weather
{
    public City CorrespondingCity { get; set; }
    public SkyState Sky { get; set; } // Example: SkyState.Clouds, SkyState.HeavySnow, etc.
    public int PrecipitationRisk { get; set; }
    public int Temperature { get; set; }
}

ในทางตรงกันข้ามฉันจะเขียนด้วยวิธีนี้เนื่องจากได้รับWeatherจาก API จากนั้นแก้ไขมันจะแปลก: การเปลี่ยนแปลงTemperatureหรือSkyจะไม่เปลี่ยนแปลงสภาพอากาศในโลกแห่งความจริงและการเปลี่ยนแปลงCorrespondingCityไม่สมเหตุสมผล

public sealed class Weather
{
    private readonly City correspondingCity;
    private readonly SkyState sky;
    private readonly int precipitationRisk;
    private readonly int temperature;

    public Weather(City correspondingCity, SkyState sky, int precipitationRisk,
        int temperature)
    {
        this.correspondingCity = correspondingCity;
        this.sky = sky;
        this.precipitationRisk = precipitationRisk;
        this.temperature = temperature;
    }

    public City CorrespondingCity { get { return this.correspondingCity; } }
    public SkyState Sky { get { return this.sky; } }
    public int PrecipitationRisk { get { return this.precipitationRisk; } }
    public int Temperature { get { return this.temperature; } }
}

3
“ ต้องใช้งานมากกว่านี้” - ต้องมีการอ้างอิง จากประสบการณ์ของฉันมันต้องใช้งานน้อยลง
Konrad Rudolph

1
@ KonradRudolph: โดยการทำงานมากขึ้นฉันหมายถึงรหัสมากขึ้นในการเขียนเพื่อสร้างชั้นไม่เปลี่ยนรูป ตัวอย่างจากคำถามของฉันแสดงสิ่งนี้โดยมี 7 บรรทัดสำหรับคลาสที่ไม่แน่นอนและ 19 สำหรับอันที่ไม่เปลี่ยนรูป
Arseni Mourzenko

คุณสามารถลดการพิมพ์รหัสได้โดยใช้คุณสมบัติ Code Snippets ใน Visual Studio หากคุณใช้งาน คุณสามารถสร้างตัวอย่างข้อมูลที่กำหนดเองของคุณและให้ IDE กำหนดเขตข้อมูลและคุณสมบัติในเวลาเดียวกันด้วยปุ่มไม่กี่ปุ่ม ประเภทที่ไม่เปลี่ยนรูปมีความจำเป็นสำหรับการใช้งานแบบมัลติเธรดและใช้อย่างกว้างขวางในภาษาเช่น Scala
Mert Akcakaya

@Mert: ข้อมูลโค้ดเหมาะสำหรับสิ่งที่ง่าย การเขียนโค้ดขนาดสั้นซึ่งจะสร้างคลาสแบบเต็มพร้อมข้อคิดเห็นของฟิลด์และคุณสมบัติและการเรียงลำดับที่ถูกต้องจะไม่ใช่เรื่องง่าย
Arseni Mourzenko

5
ฉันไม่เห็นด้วยตัวอย่างที่ให้ไว้เวอร์ชันที่ไม่เปลี่ยนรูปกำลังทำสิ่งต่าง ๆ มากขึ้น คุณสามารถลบตัวแปรระดับอินสแตนซ์โดยการประกาศคุณสมบัติด้วย accessors {get; private set;}และแม้แต่ตัวแปรที่ไม่แน่นอนควรมีตัวสร้างเนื่องจากฟิลด์เหล่านั้นทั้งหมดควรตั้งค่าเสมอและทำไมคุณไม่บังคับใช้นั้น การเปลี่ยนแปลงสองอย่างที่เหมาะสมอย่างสมบูรณ์นั้นนำมาสู่คุณลักษณะและความเท่าเทียมกันของ LoC
Phoshi

คำตอบ:


16

ฉันเขียนโปรแกรมใน C # และ Objective-C ฉันชอบการพิมพ์ที่ไม่เปลี่ยนรูป แต่ในชีวิตจริงฉันถูกบังคับให้ จำกัด การใช้งานส่วนใหญ่สำหรับประเภทข้อมูลด้วยเหตุผลต่อไปนี้:

  1. ความพยายามในการนำไปใช้งานเปรียบเทียบกับประเภทที่ไม่แน่นอน ด้วยประเภทที่ไม่เปลี่ยนรูปคุณจะต้องมีตัวสร้างที่ต้องมีข้อโต้แย้งสำหรับคุณสมบัติทั้งหมด ตัวอย่างของคุณดีมาก ลองจินตนาการว่าคุณมี 10 คลาสโดยแต่ละชั้นมีคุณสมบัติ 5-10 อย่าง เพื่อทำให้สิ่งต่าง ๆ ง่ายขึ้นคุณอาจต้องมีคลาสตัวสร้างเพื่อสร้างหรือสร้างอินสแตนซ์ที่ไม่เปลี่ยนรูปแบบที่แก้ไขในลักษณะที่คล้ายกับStringBuilderหรือUriBuilderใน C # หรือWeatherBuilderในกรณีของคุณ นี่คือเหตุผลหลักสำหรับฉันเนื่องจากคลาสที่ฉันออกแบบไม่คุ้มค่ากับความพยายาม
  2. การใช้งานของผู้บริโภค ประเภทที่ไม่เปลี่ยนรูปนั้นใช้งานยากกว่าเมื่อเทียบกับประเภทที่ไม่แน่นอน การสร้างอินสแตนซ์ต้องเริ่มต้นค่าทั้งหมด การเปลี่ยนไม่ได้ยังหมายความว่าเราไม่สามารถส่งผ่านอินสแตนซ์ไปยังวิธีการปรับเปลี่ยนค่าของมันโดยไม่ต้องใช้ตัวสร้างและถ้าเราจำเป็นต้องมีตัวสร้าง
  3. เข้ากันได้กับกรอบของภาษา เฟรมเวิร์กข้อมูลจำนวนมากต้องการชนิดที่ไม่แน่นอนและตัวสร้างเริ่มต้นเพื่อดำเนินการ ตัวอย่างเช่นคุณไม่สามารถทำการสืบค้น LINQ-to-SQL แบบซ้อนที่มีชนิดไม่เปลี่ยนรูปและคุณไม่สามารถผูกคุณสมบัติที่จะแก้ไขในโปรแกรมแก้ไขเช่นกล่องข้อความของฟอร์ม Windows

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


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

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

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

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

1
ฉันรหัสในปัจจุบันใน F # ที่ไม่สามารถเปลี่ยนเป็นค่าเริ่มต้น (จึงง่ายต่อการใช้) ฉันพบว่าจุด 3 ของคุณเป็นอุปสรรคใหญ่ ทันทีที่คุณใช้ไลบรารี. Net มาตรฐานส่วนใหญ่คุณจะต้องผ่านการวนซ้ำ (และถ้าพวกเขาใช้การสะท้อนและผ่านการเปลี่ยนแปลงไม่ได้ ... argh!)
Guran

5

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

ทำให้ฟังก์ชั่นไร้ผลข้างเคียง

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

ตัวอย่างง่ายๆหากคุณมีฟังก์ชั่นที่ทำให้เกิดผลข้างเคียงเช่นนี้:

// Make 'x' the absolute value of itself.
void make_abs(int& x);

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

// Returns the absolute value of 'x'.
int abs(int x);

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

สิ่งที่มีราคาแพงเพื่อคัดลอกเต็ม

แน่นอนว่ากรณีส่วนใหญ่นั้นไม่สำคัญหากเราต้องการหลีกเลี่ยงการทำฟังก์ชั่นที่ทำให้เกิดผลข้างเคียง กรณีการใช้งานจริงที่ซับซ้อนอาจมีลักษณะเช่นนี้มากขึ้น:

// Transforms the vertices of the specified mesh by
// the specified transformation matrix.
void transform(Mesh& mesh, Matrix4f matrix);

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

// Returns a new version of the mesh whose vertices been 
// transformed by the specified transformation matrix.
Mesh transform(Mesh mesh, Matrix4f matrix);

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

โครงสร้างข้อมูลถาวร

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

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

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

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

ค่าโสหุ้ยไม่เปลี่ยนรูป

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


3

ข้อเสียเปรียบเพียงอย่างเดียวที่ฉันคิดได้ก็คือว่าในทางทฤษฎีแล้วการใช้ข้อมูลที่ไม่เปลี่ยนรูปอาจจะช้ากว่าที่ไม่แน่นอน - มันจะช้ากว่าในการสร้างอินสแตนซ์ใหม่และรวบรวมอันก่อนหน้านี้

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

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

และเพื่อตอบคำถาม " ทำไมรูปแบบที่ไม่เปลี่ยนรูปแบบจึงไม่ค่อยถูกนำไปใช้ในแอปพลิเคชั่นอื่น ๆ ? " - ฉันไม่คิดว่ามันจะเป็น ... ทุกที่ที่คุณมองทุกคนแนะนำให้ชั้นเรียนของคุณไม่เปลี่ยนรูปแบบhttp://www.javapractices.com/topic/TopicAction.do?Id=29


1
ทั้งสองปัญหาของคุณไม่ได้อยู่ใน Haskell
Florian Margaine

@FlorianMargaine คุณช่วยอธิบายได้ไหม?
mrpyo

ความเชื่องช้าไม่เป็นความจริงต้องขอบคุณผู้รวบรวมอัจฉริยะ และใน Haskell แม้ I / O จะผ่าน API ที่ไม่เปลี่ยนรูป
Florian Margaine

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

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

0

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

  • ใช้การอ้างอิงที่ไม่แน่นอนกับวัตถุที่ไม่เปลี่ยนรูป
  • ใช้การอ้างอิงที่ไม่เปลี่ยนรูปแบบไปยังวัตถุที่ไม่แน่นอน
  • การใช้การอ้างอิงที่ไม่แน่นอนกับวัตถุที่ไม่แน่นอน

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

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


0

ในกรณีของคุณคำตอบส่วนใหญ่เนื่องจาก C # มีการสนับสนุนไม่ดีสำหรับ Immutability ...

มันจะดีถ้า:

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

  • วิธีการกลายพันธุ์ ( With) จะพร้อมใช้งานโดยอัตโนมัติ - แม้ว่าจะสามารถดูได้ด้วย

  • จะมีวิธีที่จะบอกว่าผลลัพธ์ของการเรียกใช้เมธอดที่เจาะจง (เช่นImmutableList<T>.Add) ไม่สามารถละทิ้งได้หรืออย่างน้อยก็จะสร้างคำเตือน

  • และส่วนใหญ่หากคอมไพเลอร์สามารถทำให้มั่นใจได้มากที่สุดเท่าที่จะเป็นไปได้เมื่อมีการร้องขอ (ดูhttps://github.com/dotnet/roslyn/issues/159 )


1
ถึงจุดที่สาม ReSharper มีMustUseReturnValueAttributeแอตทริบิวต์แบบกำหนดเองที่ทำเช่นนั้น PureAttributeมีผลเหมือนกันและดียิ่งขึ้นสำหรับสิ่งนี้
Sebastian Redl

-1

ทำไมประเภทที่ไม่เปลี่ยนรูปแบบจึงไม่ค่อยถูกใช้ในแอปพลิเคชันอื่น

ไม่รู้? ขาดประสบการณ์?

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


"วิศวกรที่ยังไม่ทันสมัย": เราสามารถพูดได้ว่าวิศวกรควรเรียนรู้เกี่ยวกับเทคโนโลยีที่ไม่สำคัญ ความคิดเรื่องการเปลี่ยนไม่ได้เพิ่งจะกลายเป็นกระแสหลัก แต่เป็นแนวคิดที่ค่อนข้างเก่าและได้รับการสนับสนุน (ถ้าไม่บังคับใช้) โดยภาษาที่เก่ากว่าเช่น Scheme, SML, Haskell ดังนั้นใครก็ตามที่คุ้นเคยกับการมองข้ามภาษาหลักสามารถเรียนรู้ได้แม้กระทั่งเมื่อ 30 ปีก่อน
Giorgio

@Giorgio: ในบางประเทศวิศวกรจำนวนมากยังคงเขียน C # code โดยไม่มี LINQ, ไม่มี FP, ไม่มีตัววนซ้ำและไม่มี generics จริง ๆ แล้วพวกเขาคิดถึงทุกอย่างที่เกิดขึ้นกับ C # ตั้งแต่ปี 2003 หากพวกเขาไม่รู้ภาษาที่พวกเขาชอบ ฉันคิดว่าพวกเขาแทบจะไม่รู้จักภาษาที่ไม่สำคัญ
Arseni Mourzenko

@MainMa: ดีที่คุณเขียนคำว่าวิศวกรเป็นตัวเอียง
Giorgio

@Giorgio: ในประเทศของพวกเขาจะเรียกว่าสถาปนิก , ที่ปรึกษาและจำนวนมากของคำโอ้อวดอื่น ๆ ไม่เคยเขียนในตัวเอน ใน บริษัท ที่ฉันทำงานอยู่ตอนนี้ฉันเรียกว่านักพัฒนาซอฟต์แวร์และฉันคาดว่าจะใช้เวลาในการเขียน CSS สำหรับรหัส HTML ที่ล้าสมัย ชื่องานกำลังก่อกวนในหลาย ๆ ระดับ
Arseni Mourzenko

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