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