สารบัญ:

วิธีทำ Singleton Design Pattern ใน C ++: 9 ขั้นตอน
วิธีทำ Singleton Design Pattern ใน C ++: 9 ขั้นตอน

วีดีโอ: วิธีทำ Singleton Design Pattern ใน C ++: 9 ขั้นตอน

วีดีโอ: วิธีทำ Singleton Design Pattern ใน C ++: 9 ขั้นตอน
วีดีโอ: Factory Method Design Pattern 2024, มิถุนายน
Anonim
วิธีทำรูปแบบการออกแบบซิงเกิลตันใน C ++
วิธีทำรูปแบบการออกแบบซิงเกิลตันใน C ++

บทนำ:

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

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

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

คู่มือแนะนำนี้จะใช้เวลาประมาณ 10-15 นาทีโดยเฉลี่ย

ข้อกำหนดด้านวัสดุ:

- คอมพิวเตอร์ (อาจเป็น PC หรือ Mac) ที่สามารถเรียกใช้ Visual Studios (เวอร์ชันใดก็ได้)

- โปรแกรมง่าย ๆ ที่สร้างขึ้นใน Visual Studios ซึ่งคุณสามารถทดสอบซิงเกิลตันของคุณด้วย

หมายเหตุ: รูปแบบการออกแบบซิงเกิลตันสามารถทำได้บน C++ อื่นๆ ที่รองรับ IDE หรืออินเทอร์เฟซการเข้ารหัส แต่สำหรับชุดคำสั่งนี้ เราจะใช้ Visual Studios Enterprise Edition

ขั้นตอนที่ 1: สร้างชั้นเรียนของคุณด้วยไฟล์ส่วนหัวและไฟล์ CPP

สร้างชั้นเรียนของคุณด้วยไฟล์ส่วนหัวและไฟล์ CPP
สร้างชั้นเรียนของคุณด้วยไฟล์ส่วนหัวและไฟล์ CPP
สร้างชั้นเรียนของคุณด้วยไฟล์ส่วนหัวและไฟล์ CPP
สร้างชั้นเรียนของคุณด้วยไฟล์ส่วนหัวและไฟล์ CPP

ในการสร้างไฟล์สองไฟล์และคลาสพร้อมกัน ให้เปิดโปรเจ็กต์ / โปรแกรมของคุณใน Visual Studios ไปที่ตัวสำรวจโซลูชัน คลิกขวา และกล่องจะปรากฏขึ้นใกล้กับเคอร์เซอร์ของคุณ ค้นหาตัวเลือก "เพิ่ม" โฮเวอร์ เหนือมัน และอีกกล่องหนึ่งควรปรากฏทางขวา ในกล่องนี้ คุณต้องการค้นหาตัวเลือก “New Item..” คลิกมันและหน้าต่างที่คล้ายกับรูปภาพ 1.1 รูปภาพด้านล่างจะปรากฏขึ้น ในหน้าต่างนี้ คุณต้องการเลือก "C ++ Class" จากนั้นกด "Add" ซึ่งจะเป็นการเปิดหน้าต่างอื่นที่คล้ายกับรูปภาพ 1.2 รูปภาพ ในหน้าต่างนี้ คุณพิมพ์ชื่อชั้นเรียนของคุณในฟิลด์ "ชื่อคลาส" และ Visual Studios จะตั้งชื่อไฟล์จริงตามชื่อคลาสโดยอัตโนมัติ สำหรับจุดประสงค์ของคำแนะนำนี้ เราจะตั้งชื่อคลาสของเราว่า "EngineDebugSingleton" แต่อาจเป็นชื่อที่เป็นตัวอักษรก็ได้ ตอนนี้คุณสามารถกด “ตกลง” และดำเนินการไปยังขั้นตอนที่ 2

หมายเหตุ: ตัวสำรวจโซลูชันและตำแหน่งที่เก็บไฟล์บนคอมพิวเตอร์ของคุณแยกจากกัน การย้ายหรือสร้างสิ่งใดๆ ในตัวสำรวจโซลูชันจะไม่ย้ายหรือจัดระเบียบไฟล์ภายในตัวสำรวจไฟล์ OS ของคุณ วิธีที่ปลอดภัยในการจัดระเบียบไฟล์ของคุณในด้าน file explorer จะถูกลบออก แต่ไม่ลบไฟล์เฉพาะออกจากตัวสำรวจโซลูชัน ย้ายไฟล์เดียวกันในตัวสำรวจไฟล์ไปยังตำแหน่งที่ต้องการ จากนั้นกลับไปที่ตัวสำรวจโซลูชัน คลิกขวา ค้นหาตัวเลือก "เพิ่ม" จากนั้นค้นหา "รายการที่มีอยู่" และค้นหาไฟล์ที่คุณย้าย ตรวจสอบให้แน่ใจว่าคุณย้ายทั้งส่วนหัวและไฟล์ cpp

ขั้นตอนที่ 2: ตั้งค่าตัวสร้างเป็นส่วนตัว

ตั้งค่าตัวสร้างเป็นส่วนตัว
ตั้งค่าตัวสร้างเป็นส่วนตัว

ด้วยไฟล์ CPP ที่สร้างขึ้นใหม่และไฟล์ส่วนหัว หากไฟล์ไม่เปิดโดยอัตโนมัติเมื่อคุณสร้าง ให้ไปที่ตัวสำรวจโซลูชันแล้วคลิกและเปิด "EngineDebugSingleton.h" จากนั้นคุณจะได้รับการต้อนรับด้วย “EngineDebugSingleton()” ตัวสร้างเริ่มต้นของคลาสและ “~EngineDebugSingleton()” ตัวทำลายคลาส สำหรับขั้นตอนนี้ เราต้องการตั้งค่าคอนสตรัคเตอร์เป็นไพรเวต ซึ่งหมายความว่าฟังก์ชันนี้จะใช้ได้เฉพาะกับคลาสเท่านั้น ไม่มีอย่างอื่น ด้วยวิธีนี้ คุณจะไม่สามารถสร้างตัวแปรหรือจัดสรรคลาสให้กับหน่วยความจำภายนอกคลาสได้ เฉพาะในไฟล์ส่วนหัวของคลาสและฟังก์ชันอื่นๆ ของคลาสเท่านั้น การมีคอนสตรัคเตอร์ส่วนตัวเป็นกุญแจสำคัญในการออกแบบรูปแบบและวิธีการทำงานของซิงเกิลตัน เราจะค้นพบในขั้นตอนต่อไปว่าจะสร้างอินสแตนซ์และเข้าถึงซิงเกิลตันได้อย่างไร

ตอนนี้คลาสควรมีลักษณะเช่นนี้หลังจากย้าย Constructor เป็นแบบส่วนตัว (ดูรูปที่เชื่อมโยง)

ขั้นตอนที่ 3: ตั้งค่า Destructor เป็นส่วนตัว

ตั้งค่า Destructor เป็นส่วนตัว
ตั้งค่า Destructor เป็นส่วนตัว

เช่นเดียวกับที่เราทำกับตัวสร้างใน

ขั้นตอนที่ 2 สำหรับขั้นตอนนี้ เราจะตั้งค่า destructor เป็นส่วนตัว เช่นเดียวกับตัวสร้าง ไม่มีอะไรเลย ยกเว้นตัวคลาสเอง จะสามารถลบตัวแปรใดๆ ของคลาสออกจากหน่วยความจำได้

ชั้นเรียนควรมีลักษณะเช่นนี้หลังจากเสร็จสิ้นขั้นตอนนี้ (ดูภาพที่เกี่ยวข้อง)

ขั้นตอนที่ 4: การสร้างตัวแปรพอยน์เตอร์แบบคงที่ในซิงเกิลตัน

การสร้างตัวแปรพอยน์เตอร์แบบคงที่ในซิงเกิลตัน
การสร้างตัวแปรพอยน์เตอร์แบบคงที่ในซิงเกิลตัน

ในขั้นตอนนี้ เราจะสร้าง a

ตัวแปรตัวชี้แบบคงที่ประเภท “EngineDebugSingleton*” นี่จะเป็นตัวแปรที่จะใช้ในการจัดสรรซิงเกิลตันของเราไปยังหน่วยความจำ และจะชี้ไปที่ตัวแปรนั้นตลอดเวลาที่ซิงเกิลตันของเราถูกจัดสรรไปยังหน่วยความจำ

นี่คือลักษณะของไฟล์ส่วนหัวของเราหลังจากสร้างตัวแปรนี้แล้ว

ขั้นตอนที่ 5: การสร้างฟังก์ชันอินสแตนซ์

การสร้างฟังก์ชันอินสแตนซ์
การสร้างฟังก์ชันอินสแตนซ์

ตอนนี้เราต้องการสร้างตัวอย่าง

การทำงาน. ฟังก์ชันจะต้องเป็นฟังก์ชันแบบสแตติกและต้องการส่งคืนการอ้างอิงถึงคลาสของเรา (“EngineDebugSingleton&”) เราเรียกฟังก์ชันของเราว่า Instance() ในฟังก์ชัน เราจะต้องการทดสอบก่อนว่า ptrInstance == nullptr (สามารถย่อให้เหลือ !ptrInstance) หรือไม่ หากเป็น nullptr แสดงว่าซิงเกิลตันยังไม่ได้รับการจัดสรร และอยู่ในขอบเขตของคำสั่ง if เราจะ ต้องการจัดสรรโดยทำ ptrInstance = new EngineDebugSingleton() นี่คือที่ที่คุณจัดสรรซิงเกิลตันให้กับหน่วยความจำจริงๆ หลังจากออกจากขอบเขตของคำสั่ง if แล้ว เราจะส่งคืนสิ่งที่ ptrInstance ชี้ไป ซึ่งแสดงโดยไวยากรณ์ “*ptrInstance” เราจะใช้ฟังก์ชันนี้อย่างหนักเมื่อสร้างฟังก์ชันสาธารณะแบบสแตติก ดังนั้นเราจึงสามารถตรวจสอบเพื่อดูว่าซิงเกิลตันถูกสร้างขึ้นและจัดสรรให้กับหน่วยความจำหรือไม่ โดยพื้นฐานแล้ว ฟังก์ชันนี้ทำให้คุณสามารถมีการจัดสรรชั้นเรียนได้เพียงครั้งเดียวเท่านั้น และไม่มีอีกต่อไป

นี่คือสิ่งที่คลาสของเราควรมีลักษณะเช่นนี้หลังจากสร้างฟังก์ชัน Instance() อย่างที่คุณเห็น สิ่งที่เราทำทั้งหมดยังคงอยู่ในส่วนส่วนตัวของชั้นเรียน ซึ่งจะมีการเปลี่ยนแปลงเล็กน้อยในไม่กี่ขั้นตอนถัดไป

ขั้นตอนที่ 6: การสร้างฟังก์ชันสาธารณะแบบคงที่

การสร้างฟังก์ชันสาธารณะแบบคงที่
การสร้างฟังก์ชันสาธารณะแบบคงที่
การสร้างฟังก์ชันสาธารณะแบบคงที่
การสร้างฟังก์ชันสาธารณะแบบคงที่
การสร้างฟังก์ชันสาธารณะแบบคงที่
การสร้างฟังก์ชันสาธารณะแบบคงที่

หลังจากที่คุณได้ทำหน้าที่จาก

ขั้นตอนที่ 5 คุณสามารถเริ่มสร้างฟังก์ชันสาธารณะแบบคงที่ได้ ทุกฟังก์ชันสาธารณะควรมีฟังก์ชันส่วนตัวที่เข้ากันได้ ชื่อของฟังก์ชันนี้จะต้องไม่เหมือนกัน เหตุใดจึงทำให้ฟังก์ชันคงที่ เรากำลังทำให้ฟังก์ชันสาธารณะเป็นแบบคงที่เพื่อให้สามารถเข้าถึงได้โดยไม่ต้องมีวัตถุจริง ดังนั้นแทนที่จะทำบางอย่างเช่น “EngineDebugSingleObj->SomeFunction()” เราทำ “EngineDebugSingleton:: Some Function()” ซึ่งทำให้สามารถเข้าถึงซิงเกิลตันได้ทุกที่ในโค้ด หากคุณได้ #included ไฟล์ส่วนหัวในไฟล์โปรเจ็กต์เฉพาะที่คุณกำลังทำงานด้วย ด้วยวิธีนี้ คุณยังสามารถสร้างซิงเกิลตันผ่านฟังก์ชันสาธารณะใดๆ ก็ได้

สำหรับวัตถุประสงค์ของเราในขั้นตอนนี้ เราได้สร้างฟังก์ชันโมฆะคงที่สาธารณะขึ้นสองฟังก์ชัน ได้แก่ “add()” และ “subtract()” ในส่วนส่วนตัว เรามีอีกสองฟังก์ชันคือ “PrivAdd()” และ “PrivSubtract()” นอกจากนี้เรายังเพิ่มตัวแปร int ที่เรียกว่า “NumberOfThings” คำจำกัดความของฟังก์ชันเหล่านี้จะอยู่ในไฟล์ CPP ของชั้นเรียน เพื่อให้ฟังก์ชันเข้าสู่ไฟล์ CPP อย่างง่ายดาย คุณไฮไลต์ด้วยเคอร์เซอร์ที่ฟังก์ชัน ซึ่งควรมีเส้นสีเขียวอยู่ข้างใต้ แล้วกด "Left ALT + ENTER" จะให้ตัวเลือกสร้างคำจำกัดความใน ไฟล์ CPP ที่เกี่ยวข้องของคลาส ดูรูปภาพ 6.1 เพื่อดูว่าไฟล์ส่วนหัวควรมีลักษณะอย่างไร และหลังจากที่คุณสร้างคำจำกัดความของฟังก์ชันทั้งหมดแล้ว CPP ของคุณควรมีลักษณะเหมือนรูปภาพ 6.2 ยกเว้นว่าข้อกำหนดของฟังก์ชันจะไม่มีโค้ดอยู่ในนั้น

ตอนนี้คุณจะต้องการเพิ่มโค้ดเดียวกันกับในรูปภาพ 6.2 ลงในคำจำกัดความของฟังก์ชันของคุณ ตามที่ระบุไว้ก่อนหน้านี้ ฟังก์ชันสาธารณะของเราจะใช้ประโยชน์จากฟังก์ชัน Instance() ซึ่งจะส่งคืนสิ่งที่ ptrInstance ชี้ไป ซึ่งช่วยให้เราเข้าถึงฟังก์ชันส่วนตัวของชั้นเรียนได้ ด้วยฟังก์ชันสาธารณะของ singleton คุณควรเรียกใช้ฟังก์ชันอินสแตนซ์นั้นเท่านั้น ข้อยกเว้นเพียงอย่างเดียวคือฟังก์ชันยุติของเรา

หมายเหตุ: ไม่จำเป็นต้องใช้ฟังก์ชันสาธารณะและส่วนตัวที่แสดงในขั้นตอนนี้ คุณสามารถมีชื่อฟังก์ชันและการดำเนินการที่แตกต่างกันในฟังก์ชันส่วนตัว แต่สำหรับฟังก์ชันสาธารณะประเภทใดก็ได้ คุณควรมีฟังก์ชันส่วนตัวที่เข้ากันได้และ ฟังก์ชันสาธารณะควรใช้ ในกรณีของเรา ฟังก์ชัน Instance()

ขั้นตอนที่ 7: การสร้างฟังก์ชันยุติ

การสร้างฟังก์ชันยุติ
การสร้างฟังก์ชันยุติ
การสร้างฟังก์ชันยุติ
การสร้างฟังก์ชันยุติ

เนื่องจากเราสามารถจัดสรรเฉพาะซิงเกิลของเราจากหน่วยความจำในคลาสของเรา เราจึงต้องสร้างฟังก์ชันสาธารณะแบบคงที่ ฟังก์ชันนี้จะเรียก delete บน ptrInstance ซึ่งเรียก class destructor จากนั้นเราจะต้องการตั้งค่า ptrInstance กลับเป็น nullptr เพื่อให้สามารถจัดสรรได้อีกครั้งหากโปรแกรมของคุณไม่สิ้นสุด คุณจะต้องยุติ Singletons ของคุณเพื่อล้างหน่วยความจำที่จัดสรรที่คุณจัดสรรไว้ในตัวแปรส่วนตัวของ Singleton

ขั้นตอนที่ 8: การตั้งค่า PtrInstance เป็น Nullptr

การตั้งค่า PtrInstance เป็น Nullptr
การตั้งค่า PtrInstance เป็น Nullptr

ในการทำให้ซิงเกิลตันของคุณสมบูรณ์ คุณต้องไปที่ไฟล์ EngineDebugSingleton. CPP และที่ด้านบนของไฟล์ CPP ในอินสแตนซ์ของเรา ให้พิมพ์ “EngineDebugSingleton* EngineDebugSingleton::ptrInstance = nullptr”

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

ขั้นตอนที่ 9: ทดสอบและสรุป

ทดสอบและสรุปผล
ทดสอบและสรุปผล

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

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

ไฟล์ส่วนหัวสุดท้ายของคุณควรมีลักษณะเหมือนรูปภาพ 7.1 ไฟล์ CPP ที่เกี่ยวข้องของ singleton ควรมีลักษณะเหมือน Photo 6.2 โดยมีการเพิ่มโค้ดที่แสดงในขั้นตอนที่ 8 ที่ด้านบนสุดของไฟล์ คำแนะนำนี้ให้โครงสร้างที่เรียบง่ายของ Singleton Design Pattern

คำแนะนำในการแก้ไขปัญหา:

ได้รับข้อผิดพลาดเกี่ยวกับหน่วยความจำ?

ตรวจสอบให้แน่ใจว่าคุณอ้างถึงขั้นตอนที่ 7 และขั้นตอนที่ 8 เพื่อให้แน่ใจว่าคุณกำลังตั้งค่า ptrInstance เป็น nullptr

วนซ้ำไม่มีที่สิ้นสุดเกิดขึ้น?

ตรวจสอบให้แน่ใจว่าสำหรับฟังก์ชันสาธารณะ ในคำจำกัดความ คุณกำลังเรียกใช้ฟังก์ชันส่วนตัว ไม่ใช่ฟังก์ชันสาธารณะแบบเดียวกัน

วัตถุที่จัดสรรภายในซิงเกิลตันทำให้เกิดการรั่วไหลของหน่วยความจำ?

ตรวจสอบให้แน่ใจว่าคุณเรียกใช้ฟังก์ชันการสิ้นสุดของ singleton เมื่อเหมาะสมภายในโค้ดโปรแกรมของคุณ และใน destructor ของ singleton ของคุณ ตรวจสอบให้แน่ใจว่าคุณยกเลิกการจัดสรรอ็อบเจ็กต์ใดๆ ที่จัดสรรให้กับหน่วยความจำภายในขอบเขตของโค้ด singleton