คำตอบด้านล่างไม่ถูกต้อง แต่ฉันจะเก็บไว้เพื่อให้ผู้อื่นได้เรียนรู้จากมัน (ดูด้านล่าง)
ในExampleAคุณสามารถใช้Configอินสแตนซ์เดียวกันกับหลายคลาสได้ อย่างไรก็ตามหากมีควรจะมีเพียงหนึ่งConfigตัวอย่างในการประยุกต์ใช้ทั้งพิจารณาถึงการใช้รูปแบบเดี่ยวบนเพื่อหลีกเลี่ยงกรณีหลายConfig Configและถ้าConfigเป็นซิงเกิลคุณสามารถทำสิ่งต่อไปนี้แทน:
class ExampleA
{
private $config;
public function __construct()
{
$this->config = Config->getInstance();
}
}
$exampleA = new ExampleA();
ในExampleBในมืออื่น ๆ คุณจะเคยได้รับอินสแตนซ์ที่แยกต่างหากจากตัวอย่างของแต่ละConfigExampleB
เวอร์ชันที่คุณควรใช้นั้นขึ้นอยู่กับว่าแอปพลิเคชันจะจัดการกับอินสแตนซ์ของConfig:
- ถ้าอินสแตนซ์ของแต่ละ
ExampleXควรมีอินสแตนซ์ที่แยกต่างหากจากConfigไปกับExampleB;
- ถ้าอินสแตนซ์ของแต่ละ
ExampleXจะแบ่งปันหนึ่ง (และมีเพียงหนึ่ง) ตัวอย่างของConfigการใช้ExampleA with Config Singleton;
- ถ้ากรณี
ExampleXอาจจะใช้อินสแตนซ์ที่แตกต่างกันของการติดกับConfigExampleA
ทำไมการแปลงConfigเป็นซิงเกิลตันผิด:
ฉันต้องยอมรับว่าฉันเรียนรู้เกี่ยวกับรูปแบบซิงเกิลเมื่อวานนี้เท่านั้น (อ่านหนังสือรูปแบบการออกแบบหัวเล่มแรก ) อย่างไร้เดียงสาฉันไปและนำไปใช้กับตัวอย่างนี้ แต่ตามที่หลายคนชี้ให้เห็นวิธีหนึ่งเป็นอีกวิธีหนึ่ง (บางคนมีความลับมากกว่าและบอกว่า "คุณทำผิด!") นี่ไม่ใช่ความคิดที่ดี ดังนั้นเพื่อป้องกันผู้อื่นจากการทำผิดพลาดแบบเดียวกับที่ฉันเพิ่งทำนี่เป็นบทสรุปของสาเหตุที่รูปแบบของซิงเกิลตันอาจเป็นอันตราย (ตามความคิดเห็นและสิ่งที่ฉันค้นพบกูเกิ้ล):
หากExampleAดึงข้อมูลอ้างอิงของตนเองไปยังConfigอินสแตนซ์คลาสจะถูกผนวกเข้าด้วยกันอย่างแน่นหนา จะไม่มีวิธีใดในการใช้อินสแตนซ์ของExampleAการใช้เวอร์ชันอื่นConfig(พูดบางคลาสย่อย) นี้เป็นที่น่ากลัวถ้าคุณต้องการที่จะทดสอบExampleAการใช้อินสแตนซ์จำลองขึ้นจากที่มีวิธีที่จะให้มันไปที่ใดConfigExampleA
สถานที่ตั้งของจะมีหนึ่งและเพียงหนึ่งตัวอย่างของConfigอาจจะถือในขณะนี้แต่คุณไม่สามารถมั่นใจได้ว่าจะถือเดียวกันในอนาคต หากในเวลาต่อมาปรากฎว่าต้องการอินสแตนซ์หลายรายการConfigจะไม่มีทางประสบความสำเร็จได้หากไม่เขียนโค้ดใหม่
แม้ว่าอินสแตนซ์ที่หนึ่งเดียวเท่านั้นConfigอาจจะเป็นจริงสำหรับนิรันดร์ทั้งหมด แต่อาจเกิดขึ้นได้ที่คุณต้องการใช้คลาสย่อยบางส่วนของConfig(ในขณะที่ยังมีอินสแตนซ์เดียวเท่านั้น) แต่เนื่องจากรหัสได้รับอินสแตนซ์โดยตรงผ่านgetInstance()จากConfigซึ่งเป็นstaticวิธีการจึงไม่มีวิธีรับคลาสย่อย ต้องเขียนรหัสอีกครั้ง
ความจริงที่ว่าExampleAการใช้งานConfigจะถูกซ่อนไว้อย่างน้อยเมื่อเพียงแค่ดู API ExampleAของ สิ่งนี้อาจหรือไม่อาจเป็นสิ่งที่ไม่ดี แต่โดยส่วนตัวฉันรู้สึกว่าสิ่งนี้รู้สึกเหมือนเสียเปรียบ ตัวอย่างเช่นเมื่อทำการบำรุงรักษาไม่มีวิธีง่ายๆในการค้นหาว่าคลาสใดจะได้รับผลกระทบจากการเปลี่ยนแปลงConfigโดยไม่ต้องพิจารณาการนำไปใช้ของคลาสอื่น ๆ
แม้ว่าข้อเท็จจริงที่ว่าการExampleAใช้ซิงเกิลตัน Configนั้นไม่ใช่ปัญหาในตัวมันเองมันก็อาจจะกลายเป็นปัญหาจากมุมมองการทดสอบ วัตถุSingletonจะมีสถานะซึ่งจะคงอยู่จนกว่าจะมีการยกเลิกแอปพลิเคชัน นี่อาจเป็นปัญหาเมื่อเรียกใช้การทดสอบหน่วยตามที่คุณต้องการให้การทดสอบหนึ่งแยกออกจากการทดสอบอื่น (เช่นการทดสอบที่ดำเนินการอย่างใดอย่างหนึ่งจะไม่ส่งผลกระทบต่อผลการทดสอบอื่น) ในการแก้ไขปัญหานี้วัตถุSingletonจะต้องถูกทำลายระหว่างการทดสอบแต่ละครั้ง (อาจต้องรีสตาร์ทแอปพลิเคชันทั้งหมด) ซึ่งอาจใช้เวลานาน (ไม่ต้องพูดถึงน่าเบื่อและน่ารำคาญ)
ต้องบอกว่านี้ฉันดีใจที่ฉันทำผิดที่นี่และไม่ได้ใช้งานจริง อันที่จริงแล้วฉันกำลังพิจารณาที่จะเขียนรหัสล่าสุดของฉันใหม่เพื่อใช้รูปแบบซิงเกิลสำหรับบางคลาส แม้ว่าฉันสามารถย้อนกลับการเปลี่ยนแปลงได้อย่างง่ายดาย (แน่นอนว่าทุกอย่างถูกเก็บไว้ใน SVN) แต่ฉันก็ยังต้องเสียเวลาในการทำเช่นนั้น