มันเป็นสิ่งสำคัญที่จะแยกแยะความแตกต่างระหว่างที่นี่กรณีเดียวและรูปแบบการออกแบบโทน
อินสแตนซ์เดียวเป็นเพียงความจริง แอพส่วนใหญ่ได้รับการออกแบบให้ทำงานกับการกำหนดค่าได้ครั้งละหนึ่ง UI ต่อครั้งระบบไฟล์ทีละระบบและอื่น ๆ หากมีสถานะหรือข้อมูลจำนวนมากที่จะรักษาไว้แน่นอนว่าคุณต้องการมีเพียงอินสแตนซ์เดียวและทำให้มันมีชีวิตอยู่ได้นานที่สุด
รูปแบบการออกแบบ Singleton เป็นประเภทของอินสแตนซ์เดี่ยวที่เฉพาะเจาะจงอย่างยิ่ง
- สามารถเข้าถึงได้ผ่านฟิลด์อินสแตนซ์ส่วนกลาง
- สร้างทั้งในการเริ่มต้นโปรแกรมหรือการเข้าถึงครั้งแรก;
- ไม่มีตัวสร้างสาธารณะ (ไม่สามารถยกตัวอย่างโดยตรง)
- ไม่เคยเป็นอิสระอย่างชัดเจน (เป็นอิสระจากการยกเลิกโปรแกรมโดยปริยาย)
เป็นเพราะตัวเลือกการออกแบบที่เฉพาะเจาะจงนี้ซึ่งรูปแบบดังกล่าวนำเสนอปัญหาระยะยาวหลายประการที่อาจเกิดขึ้น:
- ไม่สามารถใช้คลาส abstract หรืออินเตอร์เฟส
- ไม่สามารถคลาสย่อย;
- การมีเพศสัมพันธ์สูงทั่วทั้งแอปพลิเคชัน (ยากที่จะแก้ไข);
- ทดสอบยาก (ไม่สามารถปลอม / จำลองในการทดสอบหน่วย)
- ยากต่อการขนานในกรณีที่สถานะไม่แน่นอน (ต้องล็อคอย่างกว้างขวาง);
- และอื่น ๆ
ไม่มีอาการเหล่านี้ที่เกิดเฉพาะถิ่นกับอินสแตนซ์เดี่ยวเพียงรูปแบบซิงเกิล
คุณสามารถทำอะไรแทน อย่าใช้รูปแบบซิงเกิล
อ้างจากคำถาม:
แนวคิดคือให้มีที่นี่ในแอปที่เก็บข้อมูลและซิงค์จากนั้นหน้าจอใหม่ใด ๆ ที่เปิดขึ้นสามารถสืบค้นสิ่งที่ต้องการจากที่นั่นได้โดยไม่ต้องทำคำขอซ้ำสำหรับข้อมูลสนับสนุนต่าง ๆ จากเซิร์ฟเวอร์ การร้องขอไปยังเซิร์ฟเวอร์อย่างต่อเนื่องจะใช้แบนด์วิดท์มากเกินไป - และฉันกำลังพูดถึงค่าใช้จ่ายอินเทอร์เน็ตเพิ่มเติมหลายพันดอลลาร์ต่อสัปดาห์ดังนั้นจึงไม่เป็นที่ยอมรับ
แนวคิดนี้มีชื่อตามที่คุณเรียงลำดับของคำใบ้ แต่เสียงไม่แน่ใจ มันเรียกว่าแคช หากคุณต้องการจินตนาการคุณสามารถเรียกมันว่า "แคชออฟไลน์" หรือเพียงแค่สำเนาข้อมูลระยะไกลแบบออฟไลน์
แคชไม่จำเป็นต้องเป็นซิงเกิลตัน มันอาจจะต้องมีเช่นเดียวถ้าคุณต้องการที่จะหลีกเลี่ยงการเรียกข้อมูลเดียวกันสำหรับกรณีแคชหลาย ๆ แต่ไม่ได้หมายความว่าคุณจะมีการเปิดเผยทุกอย่างเพื่อให้ทุกคน
สิ่งแรกที่ฉันจะทำคือแยกส่วนการทำงานต่างๆของแคชออกเป็นส่วนต่อประสานที่แยกจากกัน ตัวอย่างเช่นสมมติว่าคุณกำลังทำตัว YouTube ที่แย่ที่สุดในโลกโดยอ้างอิงจาก Microsoft Access:
MSAccessCache
▲
|
+ + ----------------- ----------------- +
| | |
IMediaCache IProfileCache IPageCache
| | |
| | |
VideoPage MyAccountPage MostP PopularPage
ที่นี่คุณมีหลายอินเตอร์เฟซอธิบายเฉพาะประเภทของข้อมูลชั้นโดยเฉพาะอย่างยิ่งอาจจำเป็นต้องเข้าถึง - สื่อโปรไฟล์ผู้ใช้และหน้าคงที่ (เช่นหน้า) ทั้งหมดนี้นำไปใช้โดยแคชขนาดใหญ่ แต่คุณออกแบบคลาสของคุณเองเพื่อรับอินเทอร์เฟซแทนดังนั้นพวกเขาจึงไม่สนใจอินสแตนซ์ที่พวกเขามี คุณเริ่มต้นอินสแตนซ์ทางกายภาพหนึ่งครั้งเมื่อโปรแกรมของคุณเริ่มต้นและจากนั้นก็เริ่มส่งผ่านอินสแตนซ์ (ส่งไปยังอินเทอร์เฟซชนิดเฉพาะ) ผ่านตัวสร้างและคุณสมบัติสาธารณะ
นี่เรียกว่าการพึ่งพาการฉีดโดยวิธี; คุณไม่จำเป็นต้องใช้ในฤดูใบไม้ผลิหรือภาชนะ IoC ใด ๆ เป็นพิเศษเพียงตราบเท่าที่การออกแบบระดับทั่วไปของคุณยอมรับการอ้างอิงจากโทรแทนinstantiating พวกเขาในตัวของมันเองหรืออ้างอิงรัฐทั่วโลก
ทำไมคุณควรใช้การออกแบบตามอินเตอร์เฟส สามเหตุผล:
ทำให้โค้ดอ่านง่ายขึ้น คุณสามารถเข้าใจได้อย่างชัดเจนจากอินเทอร์เฟซว่าข้อมูลใดขึ้นอยู่กับคลาสที่พึ่งพา
ถ้าและเมื่อคุณทราบว่า Microsoft Access ไม่ใช่ตัวเลือกที่ดีที่สุดสำหรับแบ็คเอนด์ข้อมูลคุณสามารถแทนที่มันด้วยสิ่งที่ดีกว่า - สมมุติว่า SQL Server
ถ้าและเมื่อคุณตระหนักว่า SQL Server ไม่ได้เป็นทางเลือกที่ดีที่สุดสำหรับสื่อโดยเฉพาะคุณสามารถเลิกใช้งานของคุณได้โดยไม่ต้องมีผลกระทบต่อส่วนอื่น ๆ ของระบบ นั่นคือสิ่งที่พลังที่แท้จริงของสิ่งที่เป็นนามธรรมเข้ามา
หากคุณต้องการที่จะก้าวไปอีกขั้นหนึ่งคุณสามารถใช้คอนเทนเนอร์ IoC (กรอบงาน DI) เช่น Spring (Java) หรือ Unity (.NET) เกือบทุกเฟรมเวิร์ก DI จะทำการจัดการอายุการใช้งานของตนเองและอนุญาตให้คุณกำหนดบริการเฉพาะเป็นอินสแตนซ์เดียว (มักเรียกว่า "singleton" แต่นั่นเป็นเพียงเพื่อความคุ้นเคย) โดยทั่วไปเฟรมเวิร์กเหล่านี้จะช่วยให้คุณประหยัดงานลิงส่วนใหญ่ที่ผ่านไปด้วยตนเอง แต่มันไม่จำเป็นอย่างยิ่ง คุณไม่จำเป็นต้องมีเครื่องมือพิเศษใด ๆ เพื่อใช้การออกแบบนี้
เพื่อความสมบูรณ์ฉันควรชี้ให้เห็นว่าการออกแบบข้างต้นไม่เหมาะอย่างยิ่งเช่นกัน เมื่อคุณกำลังเผชิญกับแคช (เป็นคุณ) คุณจริงควรมีการแยกชั้น กล่าวอีกนัยหนึ่งการออกแบบแบบนี้:
+ - IMediaRepository
|
แคช (ทั่วไป) --------------- + - IProfileRepository
▲ |
| + - IPageRepository
+ + ----------------- ----------------- +
| | |
IMediaCache IProfileCache IPageCache
| | |
| | |
VideoPage MyAccountPage MostP PopularPage
ประโยชน์ของสิ่งนี้คือคุณไม่จำเป็นต้องแยกแยะCache
อินสแตนซ์ของคุณหากคุณตัดสินใจปรับโครงสร้าง IMediaRepository
คุณสามารถเปลี่ยนวิธีการสื่อจะถูกเก็บไว้โดยเพียงแค่การให้อาหารมันการดำเนินงานอื่นของ หากคุณคิดว่าสิ่งนี้เข้ากันได้อย่างไรคุณจะเห็นว่ามันยังคงสร้างแคชทางกายภาพเพียงอินสแตนซ์เดียวดังนั้นคุณจึงไม่จำเป็นต้องดึงข้อมูลเดียวกันซ้ำสองครั้ง
ไม่มีสิ่งใดที่จะกล่าวได้ว่าทุกชิ้นส่วนของซอฟต์แวร์ในโลกจะต้องได้รับการออกแบบให้สอดคล้องกับมาตรฐานที่เข้มงวดเหล่านี้ของการติดต่อที่แน่นหนาและการเชื่อมต่อที่หลวม ขึ้นอยู่กับขนาดและขอบเขตของโครงการทีมของคุณงบประมาณกำหนดเวลา ฯลฯ ถ้าคุณถามว่าการออกแบบที่ดีที่สุดคืออะไร (ใช้แทนซิงเกิล) นี่คือสิ่งที่
ป.ล. ตามที่คนอื่นได้กล่าวไว้อาจไม่ใช่ความคิดที่ดีที่สุดสำหรับคลาสที่ต้องพึ่งพาที่ต้องระวังว่าพวกเขากำลังใช้แคช - ซึ่งเป็นรายละเอียดการใช้งานที่พวกเขาไม่ควรสนใจ ที่ถูกกล่าวว่าสถาปัตยกรรมโดยรวมจะยังคงมีลักษณะคล้ายกันมากกับสิ่งที่ภาพข้างต้นคุณก็จะไม่ได้หมายถึงการเชื่อมต่อของแต่ละบุคคลเป็นแคช แต่คุณจะตั้งชื่อพวกเขาบริการหรือสิ่งที่คล้ายกัน