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


47

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

ฉันได้รับประโยชน์อะไรบ้างจากการเข้าเรียนstatic? ฉันหมายถึงหลังจากประกาศคลาสคงที่หนึ่งควรยังคงประกาศสมาชิกทั้งหมดที่เขา / เธอต้องการที่จะเข้าถึงได้โดยไม่ต้องเริ่มต้นเช่นเดียวกับคงที่เช่นกัน

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


หากคุณกำลังเขียนโค้ดในสไตล์ Func Prog a la Rich Hickey สิ่งนี้จะมีประโยชน์
งาน

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

คำตอบ:


32

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

Math m = new Math();

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


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

19
@Chad จากนั้นไลบรารีได้รับการออกแบบมาไม่ดี การขยายชั้นเรียนที่ไม่ได้ออกแบบมาสำหรับการขยายในท้ายที่สุดก็ใช้งานไม่ได้ดังนั้นควรทำให้ชั้นเรียนsealedเป็นที่แรก ฉันรับทราบว่าไม่ใช่ทุกคนที่เห็นด้วยกับความรู้สึกนี้ แต่ความคิดเห็นไม่ใช่ที่ที่ดีสำหรับการอภิปราย แต่ในกรณีของstaticปัญหานี้ไม่ได้ก่อให้เกิดตัวเองการสร้างอินสแตนซ์System.Mathจะไม่มีเหตุผล
Konrad Rudolph

1
@Konard ถ้าคุณประกาศให้สมาชิกทุกคนในMathชั้นเรียนเป็นแบบคงที่โดยไม่ต้องประกาศMathชั้นเรียนเป็นแบบคงที่คุณยังสามารถใช้งานได้โดยไม่จำเป็นต้องมีอินสแตนซ์
Saeed Neamati

11
@Saeed - นี่เป็นความจริง แต่คุณสามารถยกตัวอย่างคลาสได้ซึ่งไม่ได้มีวัตถุประสงค์อะไร ฉันจะทำอย่างไรกับตัวอย่างของวิชาคณิตศาสตร์? อย่างชัดเจนแสดงเจตนาของการเรียน (ไม่ instantiation จำเป็นหรือต้องการ) staticจะถูกทำเครื่องหมาย
Corbin วันที่

3
@Saeed ลองย้อนกลับมาดู: ฉันขอให้คุณอ่านคำตอบของฉันอีกครั้งเพราะคุณเข้าใจผิด: ความคิดเห็นของคุณไม่เกี่ยวข้องกับคำตอบของฉัน new Math()ฉันไม่เคยบอกว่าคุณต้องเขียน
Konrad Rudolph

24

StackOverflow มีการอภิปรายที่ดีในหัวข้อนี้ เพื่อความสะดวกในการอ้างอิงฉันจะคัดลอกและวางไว้ที่นี่ในนามของผู้เขียนMark S. Rasmussen :

ฉันเขียนความคิดของชั้นเรียนคงที่ในหัวข้อก่อนหน้า :

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

ความแตกต่าง

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

อินเทอร์เฟซเป็นทุกข์

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

การทดสอบ

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

ส่งเสริม blobs

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

พารามิเตอร์คืบ

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

เรียกร้องให้ผู้บริโภคสร้างตัวอย่างของคลาสโดยไม่มีเหตุผล

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

เฉพาะ Sith เท่านั้นที่เกี่ยวข้อง

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

มาตรฐานมาตรฐานมาตรฐาน!

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


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

2
"มีเพียงข้อตกลง Sith ในข้อสรุป" - ฉันไม่เคยเห็นแบบนั้นมาก่อนเลย .... แต่มันสมบูรณ์แบบ ทำให้ฉันฮ่า ๆ
Brook

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

1
@Rick: คำตอบที่คัดลอกค่อนข้างยาวและการถอดความมันจะช่วยได้อย่างแน่นอน แค่ประโยคเช่น "ไม่ใช่แค่ว่าพวกเขาไม่มีประโยชน์จริง ๆ พวกเขายังสามารถทำอันตรายได้เช่นเดียวกับที่โพสต์นี้แสดงให้เห็น:" จะให้ฉันข้ามอย่างรวดเร็วเพราะฉันเห็นว่าไม่ใช่ข้อมูลที่ฉันกำลังมองหา
blubb

@Simon: ฮ่า ๆ ฉัน 1 + 'ed โพสต์ของคุณ ในความพยายามที่จะเลิกโต้เถียงกับบางสิ่งที่โง่เง่าฉันจะเห็นด้วย :) หวังว่าผู้โพสต์ดั้งเดิมจะพบคำตอบ / คัดลอกและวางฉันมีประโยชน์
ริ

16

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

trait MyFoo {
  def foo: Int
  def plusFoo(a: Int) = foo + a
}

อาจแสดงใน C # เป็น

public interface IMyFoo {
  int Foo();
}

public static class MyFooExtensions {
  public static int PlusFoo(this IMyFoo f, int a) {
    return f.Foo() + a;
  }
}

คุณพบเข็มในกองหญ้า +1
Saeed Neamati

3

สำหรับฉันคลาสแบบคงที่ (ใน C #) เป็นชนิดของการเรียกใช้ฟังก์ชัน

ตัวอย่างเช่น

public static string DoSomething(string DoSomethingWithThisString){}

ฉันผ่านสตริงและกลับสตริง ทุกอย่างมีอยู่ในวิธีการนั้น ไม่มีการเข้าถึงตัวแปรสมาชิก ฯลฯ

สุจริตส่วนใหญ่การใช้งานสำหรับฉันได้รับการลดบรรทัดของรหัส:

ทำไม:

MyClass class = new MyClass();
String s = class.DoSomething("test");

เมื่อฉันสามารถทำสิ่งนี้:

String s = MyClass.DoSomething("test");

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

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

นั่นอาจจะง่าย staticแต่ที่ส่วนใหญ่เป็นวิธีการที่ฉันได้ใช้


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