แนวคิดและแนวปฏิบัติที่ดีที่สุดสำหรับคลาสและสมาชิกแบบคงที่ [ปิด]


11

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

ฉันเห็นเอนทิตีเหล่านี้เป็น "คลาส / สมาชิกยูทิลิตี้" ในแง่ที่ว่าพวกเขาไม่ต้องการหรือต้องการอินสแตนซ์ชั้นเรียนเพื่อให้การทำงาน

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

ดูตัวอย่างชั้นเรียนและสมาชิกด้านล่างเพื่อแสดงสิ่งที่ฉันกำลังอ้างอิง

// non-static class with static members
//
public class Class1
{
    // ... other non-static members ...

    public static string GetSomeString()
    {
        // do something
    }
}

// static class
//
public static class Class2
{
    // ... other static members ...

    public static string GetSomeString()
    {
        // do something
    }
}

ขอบคุณล่วงหน้า!



1
@ Robert Harvey: ถึงแม้ว่าบทความที่คุณอ้างถึงจะมีประโยชน์ แต่ก็ไม่ได้มีอะไรมากในแง่ของแนวปฏิบัติที่ดีที่สุดและข้อผิดพลาดบางอย่างเกิดขึ้นเมื่อใช้คลาสคงที่
เบอร์นาร์ด

คำตอบ:


18

โดยทั่วไปให้หลีกเลี่ยงสถิตยศาสตร์ - โดยเฉพาะอย่างยิ่งสถานะคงที่ใด ๆ

ทำไม?

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

  2. สถิตศาสตร์ทำให้เกิดปัญหากับการทดสอบหน่วย กรอบการทดสอบหน่วยใด ๆ ที่คุ้มค่าคือเกลือจะทำการทดสอบพร้อมกัน จากนั้นคุณพบเป็น # 1 ที่แย่ไปกว่านั้นคือคุณทำให้การทดสอบของคุณยุ่งยากกับการตั้งค่า / การดาวน์ทั้งหมดและแฮกเกอร์ที่คุณจะต้องลองและ "แชร์" รหัสการติดตั้ง

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

มีการใช้สถิตอย่างแน่นอน: ค่าคงที่ทำงานได้ดี วิธีการบริสุทธิ์ที่ไม่เหมาะสมในชั้นเรียนเดียวสามารถทำงานได้ดีที่นี่

แต่โดยทั่วไปหลีกเลี่ยงพวกเขา


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

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

ดังนั้นหากหนึ่งเธรดกำลังเข้าถึงสมาชิกแบบสแตติกเธรดอื่นจำเป็นต้องรอจนกระทั่งเธรดที่เป็นเจ้าของออกรีซอร์ส?
Thomas Stringer

@ThomasStringer - อาจจะไม่ สถิตศาสตร์เป็น (เกือบมากในภาษาส่วนใหญ่) ไม่แตกต่างจากทรัพยากรที่ใช้ร่วมกันอื่น ๆ ในเรื่องนี้
Telastyn

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

17

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

ถ้าฉันดูตัวอย่างรหัสของคุณเอง:

public class Class1
{
    public static string GetSomeString()
    {
        // do something
    }
}

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

ให้ยกตัวอย่างที่แตกต่าง:

public static bool IsOdd(int number) { return (number % 2) == 1; }

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

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

ในกรอบงาน. NET มีการขยายวิธีการอยู่ค่อนข้างนาน LINQมีฟังก์ชั่นส่วนขยายจำนวนมาก (เช่นEnumerable.Where () , Enumerable.First () , Enumerable.Single () , ฯลฯ ) เราไม่เห็นว่าสิ่งเหล่านี้ไม่ดีใช่ไหม

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

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

ดังนั้นตรวจสอบความสามารถในการอ่านของรหัสลูกค้าสำหรับฟังก์ชั่นนี้:

ตัวเลือก a (พร้อมฟังก์ชันที่ประกาศเป็นวิธีส่วนขยาย):

public void Execute(int number) {
    if (number.IsOdd())
        // Do something
}

ตัวเลือก b:

public void Execute(int number) {
    var helper = new NumberHelper();
    if (helper.IsOdd(number))
        // Do something
}

ฟังก์ชั่นสแตติก (ส่วนขยาย) ทำให้โค้ดชิ้นแรกอ่านง่ายขึ้นและมีความสำคัญในการอ่านมากดังนั้นให้ใช้ฟังก์ชั่นสแตติกตามความเหมาะสม

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