Saladpuk.com
🏆 เนื้อหาหลัก
🏆 เนื้อหาหลัก
  • 💖สลัดผัก
  • 📰มีอะไรใหม่บ้าง
    • 2020
      • 2020-11
      • 2020-10
      • 2020-09
      • 2020-08
      • 2020-03
      • 2020-02
      • 2020-01
    • 2019
      • 2019-12
      • 2019-11
      • 2019-10
      • 2019-09
      • 2019-08
  • 🤔อ่านเรื่องไรดี ?
  • มือใหม่หัดเขียนโค้ด
    • 👶เขียนโค้ดด้วยภาษา C#
      • เกิดมาไม่เคยเขียนโค้ดมาก่อนเบย
      • 👶พื้นฐาน
        • 1.โปรแกรมที่ต้องลง
        • 2.โครงสร้างของโค้ด
        • 3.ชนิดของข้อมูล
        • 4.การสร้างตัวแปร
        • 5.คำสั่งพื้นฐาน
        • 6.การแปลงข้อมูล
        • 7.การเปรียบเทียบค่า
        • 8.การตัดสินใจด้วย IF statements
        • 9.การตัดสินใจด้วย Switch statements
        • 10.การทำงานซ้ำๆด้วย While
        • 11.การทำงานซ้ำๆด้วย Do While
        • 12.การทำงานซ้ำๆด้วย For
        • 13.การแก้โจทย์จากรูป
        • 14.มารู้จักกับ Array กัน
      • 🧑ระดับกลาง
        • 15.Value type vs Reference type
        • 16.ลดงานซ้ำๆด้วย Method
        • 17.มารู้จักกับ Class & Field กัน
        • 18.มารู้จักกับ Constructor กันบ้าง
        • 19.มาเขียน Method ใน Class กัน
        • 20.มารู้จักกับ Property กัน
        • 21.ลองใช้คลาสแบบจริงจังบ้าง
        • 22.การสืบทอด Inheritance
        • 23.Polymorphism
        • 24.Abstract Class
        • 25.Interface
        • 26.Namespace
        • 27.Enum
        • 28.Exception handler
        • 29.ลงลึกกับ string
        • 30.StringBuilder เพื่อนคู่ string
      • 👨⏳ระดับสูง
        • Generic
        • Delegates
        • Action & Func
        • Lambda expression
        • LINQ
        • พระคัมภีร์การใช้คำสั่ง LINQ
      • 💡Tips
        • 💡C# version 8.0
        • 💡Boxing & Unboxing
    • 👶Algorithm
      • 👾Algorithm Big-O
      • 👽Algorithm P & NP
    • 👦OOP
      • 💖Abstraction
      • 💖Encapsulation
      • 🏆Abstraction & Encapsulation
      • 💖Inheritance
      • 💖Polymorphism
      • 🏆Inheritance & Polymorphism
      • 📝ลองเขียน OOP ดูดิ๊
      • 👑OOP + Power of Design
      • 🥰เทคนิคในการออกแบบ
    • 👶บทสรุปฐานข้อมูล
      • เก็บรูปในฐานข้อมูล
      • Database indexing
      • การลบข้อมูล
    • 👦Communication Patterns
    • 👦Design Patterns
      • 🤰Creational Patterns
        • 🏭Factory Method
        • 🏭Abstract Factory
        • ☝️ Singleton Pattern
        • 🏗️ Builder Pattern
        • 🎎Prototype Pattern
      • 🧱Structural Patterns
        • 🔌Adapter Pattern
        • 📪Proxy Pattern
  • Puzzle
    • 🧠Challenges
      • 🐴Google ม้า 25 ตัว
      • 🌉Amazon เสา 2 ต้น
      • 🥇ทองเก๊
      • 💊ยาต้านโควิด
      • 🎩CP หมวก 5 ใบ
      • 🧓Einstein's Riddle 01
  • พื้นฐานที่ควรต้องรู้
    • 🐳Docker
      • 📦Docker Containers
      • 🃏Docker Exercise 01
      • 🛠️ Docker Tools
      • 🗃️ Docker Registry
      • 🖼️ Container Image
      • 📢Docker Push
      • 🔄WSL
    • 👶Clean Code
      • 🧓Uncle Bob - Clean Code
      • 🧓Uncle Bob - Comments
      • 🧓Uncle Bob - Naming
      • 🧓Uncle Bob - Mindset
      • 🧓Uncle Bob - TDD
    • 👶Code Smells
    • 👶สิ่งที่คนเขียนโค้ดมักเข้าใจผิด
    • 👶AI พื้นฐาน
    • 👶Git พื้นฐาน
      • Git branching strategy
    • 👶Cloud พื้นฐาน
    • 👶UML พื้นฐาน
      • Activity Diagram
      • Class Diagram
      • Sequence Diagram
      • Use case Diagram
      • บทสรุปการใช้ UML
    • 👶Data Scientist
      • การเลือก Algorithms ให้ AI (1/5)
      • การเตรียมข้อมูลให้ AI (2/5)
      • หลักการตั้งคำถามให้ AI (3/5)
      • แฉความลับของ AI Model (4/5)
      • หัดเขียน AI จาก AI ของคนอื่น (5/5)
    • 👶DevOps พื้นฐาน
    • 👶Docker ขั้นพื้นฐาน
      • Image and Container
      • แชร์ Docker Image ที่สร้างไว้
    • 👶Microservices พื้นฐาน
      • Microservices ที่ดีมีลักษณะยังไง
      • Microservices Tips
      • จาก Monolith สู่ Microservices
    • 👶ความรู้พื้นฐานในการทำเว็บ
    • 👦Bottlenecks of Software
      • หัวใจที่สำคัญที่สุดของฐานข้อมูล
    • 👦Agile Methodology
      • Agile in a Nutshell
      • Software Development Life Cycle
      • Code Review
    • 👦Security พื้นฐาน
      • การเก็บรหัสผ่านที่ถูกต้อง
      • Security in actions
        • Hash function
      • Security Principles
      • 😎The Matrix 1
      • 😎The Matrix 2
      • HTTPS in a nutshell
    • 👦SOLID Design Principles
      • มารู้จักกับ SOLID กันดีกว่า
      • Single-Responsibility Principle
      • Open/Closed Principle
      • Liskov Substitution Principle
      • Interface Segregation Principle
      • Dependency-Inversion Principle
  • Cloud Computing
    • 👶Microsoft Azure 101
      • สมัคร Microsoft Azure
      • รู้จักกับ Resource Groups
      • สร้างเว็บตัวแรกกัน
      • สร้าง Virtual Machine กัน
      • ประเภทของคลาว์เซอร์วิส
      • มาสร้าง Logic App กัน
      • มาสร้าง Function App กัน
      • คลาว์คิดเงินยังไง ?
      • Cloud Native
      • Guideline for Cloud scaling
      • Auto Scaling
    • 👶Azure App Services
    • 👶App Service Plan
    • 👶Azure Storage
      • Blob storage
        • ลองสร้างที่เก็บไฟล์กันเลย
        • เข้าใจ Blob storage ให้มากขึ้น
        • ลองเขียนโค้ดอัพโหลดไฟล์กันบ้าง
        • สร้างเว็บจากที่ฝากไฟล์บนคลาว์
    • 👶Azure Bot Service
      • Bot เข้าใจเราได้ยังไงกันนะ
    • 👶Azure Cognitive Services
      • การสร้าง Cognitive Services
      • การ Login ด้วยใบหน้า
      • อ่านลายมือจากรูปเป็นตัวอักษร (OCR)
      • เขียน AI แยกของต่างๆทำยังไง?
      • เขียนแอพ ทายอายุ บอกเพศ ง่ายจิ๊ดเดียว
      • เขียนแอพให้ AI อธิบายรูปเป็นภาษาคน
    • 👶Machine Learning Studio
      • มาสร้าง AI ของแท้ตัวแรกของเรากัน
      • สร้าง AI ตัดสินใจอนุมัติบัตรเครดิต 💳
      • ลองเรียกใช้ AI ของเรากัน
    • 👶Azure Service Fabric
      • สร้าง Service Fabric กัน
    • 👶Blockchain
      • Blockchain ทำงานยังไง ?
      • Consensus Algorithm คืออะไร ?
      • สร้าง Blockchain ใช้เองกัน !
      • หัดเขียน Smart Contract กัน
    • 👶Power BI
    • 👶Azure Web App
      • เซิฟเวอร์บนคลาว์ ราคา? ต่าง?
    • 👶Azure DevOps
      • เล่น Azure DevOps กัน
      • เล่นกับ Repository
      • ลองทำ Continuous Integration (CI)
      • ลองทำ Continuous Delivery (CD)
      • เล่น Kanban Board
    • 🤠Cloud Playground
      • การป้องกันความลับหลุดตอนที่ 1
      • การป้องกันความลับหลุดตอนที่ 2
      • การป้องกันความลับหลุดตอนที่ 3
      • การป้องกันความลับหลุดตอนจบ
  • Software Testing
    • 👦Test-First Design
    • 👦Test-Driven Development
      • 1.มารู้จักกับ TDD กันดีกว่า
      • 2.Test cases เขาเขียนกันยังไงนะ
      • 3.เครื่องมือในการทดสอบ
      • 4.การใช้ Theory และ InlineData
      • 5.โค้ดที่ทดสอบได้
      • 6.Mantra of TDD
      • 7.Functional & None-Functional testing
      • 8.Manual vs Automation testing
      • 9.Automation Frameworks in .NET
      • 10.Mock Framework
      • 11.มาเรียนการใช้ Moq กันเถอะ
      • 12.สรุป
  • Web
    • 👦Web API
      • 1.Web API คืออะไร
      • 2.ติดตั้ง .NET Core SDK
      • 3.สร้าง Web API ตัวแรกกัน
      • 4.Verbs
      • 5.Swagger เพื่อคู่ API
      • 6.การใช้ Model
      • 7.เรียก Web API ผ่าน Postman
      • 8.มาจัดกลุ่ม API กัน (1/2)
      • 9.มาจัดกลุ่ม API กัน (2/2)
  • Software Design
    • 🤴Design Patterns
      • 🦈Creational patterns
        • Abstract Factory
        • Builder
        • Factory Method
        • Prototype
        • Singleton
      • 🦈Structural patterns
        • Adapter
        • Bridge
        • Decorator
        • Facade
        • Proxy
      • 🦈Behavioral patterns
        • Chain of Responsibility
        • Command
        • Iterator
        • Mediator
        • Memento
        • Observer
        • State
        • Strategy
        • Template Method
        • Visitor
Powered by GitBook
On this page
  • 🧐 โจทย์
  • 🧒 แก้โจทย์ครั้งที่ 1
  • 🧒 แก้โจทย์ครั้งที่ 2
  • 🔥 วิเคราะห์ปัญหา
  • 🔥 แก้ไขปัญหา
  • 🤔 Singleton คือไย ?
  • 🔥 จุดกำเหนิด
  • 🔥 ผลจากการใช้
  • 🔥 วิธีการใช้
  • 🤠 เทคนิค
  • 🔥 Lazy Initialization
  • 🔥 Early Initialization
  • 🔥 Bindable Object
  • 🥴 ข้อผิดพลาดที่เจอบ่อยๆ
  • ⛔ ใช้ static class แทน
  • ⛔ ไม่ใช้ private constructor
  • 🎯 บทสรุป
  • 👍 ข้อดี
  • 👎 ข้อเสีย
  • 🤙 ทางเลือก

Was this helpful?

Export as PDF
  1. มือใหม่หัดเขียนโค้ด
  2. Design Patterns
  3. Creational Patterns

☝️ Singleton Pattern

แนวคิดในการสร้าง object ที่มีได้เพียงตัวเดียว

PreviousAbstract FactoryNext🏗️ Builder Pattern

Last updated 5 years ago

Was this helpful?

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

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

หมายเหตุ เนื้อหาของบทความนี้จะเน้นให้เข้าใจหลักการทำงานของ Design Patterns แต่ละตัว โดยใช้เกม Ragnarok เป็นการอธิบาย ซึ่งบางอย่างอาจจะไม่ตรงกับตัวเกมจริงๆนะขอรับ Gravity อย่ามาจับผมนะผมโดนแมวน้ำครอบงำ + รู้เท่าไม่ถึงการ + ผมเป็นคนดี + ผมมีลูกมีเมียมีสามีที่ต้องดูแล 😭

🧐 โจทย์

สมมุติว่าในเกมของเรามีอีเว้นท์พิเศษตัวนึง โดยมันจะปล่อย Boss ที่ชื่อว่า Detardeurus มาให้ผู้เล่นทุกคนช่วยกันปราบ ซึ่งถ้ามีผู้เล่นคนไหนปราบมันลงได้ มันก็จะกลับมาเกิดใหม่ในทุกๆ 2 ชั่วโมง ตามรูปด้านล่าง

และด้วยความพิเศษที่มันเป็นอีเว้นท์ เลยทำให้เจ้าบอสตัวนี้จะต้อง มีได้เพียงตัวเดียวเท่านั้น และ ผู้เล่นทุกคนจะต้องเข้าถึงข้อมูลบอสตัวนี้ได้ ไม่ว่าจากที่ไหนก็ตามอีกด้วย

แล้วเราจะเขียนโค้ดออกมายังไงดี เพื่อให้มันสามารถตอบโจทย์ความต้องการแบบนี้ ได้อย่างไม่มีปัญหากันนะ ?

🧒 แก้โจทย์ครั้งที่ 1

จากที่ว่ามาก็น่าจะไม่มีอะไรยากชิมิ? ถ้าเราอยากให้บอสมันมีตัวเดียวเราก็แค่ไปสร้าง object ของบอสตัวนั้นขึ้นมา 1 ตัว แล้วเขียนเงื่อนไขลงไปว่าห้ามสร้างเกิน 1 ตัวนะจ๊ะ ตามโค้ดด้านล่างนี้ใช่ป่ะ

public class EventBoss
{
    private Detardeurus boss = new Detardeurus();

    public Detardeurus GetDetardeurus()
    {
        return boss;
    }
}

ส่วนถ้าเราอยากให้ทุกคนสามารถเข้าถึง object ตัวนี้ได้จากที่ไหนก็ได้ เราก็จะให้มันเป็น static member ยังไงล่ะ แก้โค้ดแพร๊บ

public class EventBoss
{
    private static Detardeurus boss = new Detardeurus();

    public static Detardeurus GetDetardeurus()
    {
        return boss;
    }
}

ไหนลองตรวจดูดิ๊ว่าตอนที่ไปเอา object นี้ออกมา มันจะเป็น object เดียวกันหรือเปล่านะ

static void Main(string[] args)
{
    var boss1 = EventBoss.GetDetardeurus();
    var boss2 = EventBoss.GetDetardeurus();

    Console.WriteLine(boss1 == boss2);
}

ผลลัพท์ True

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

เสียใจด้วยนะมันไม่ได้ง่ายแบบนั้นหรอก แม้ว่าเราจะได้ object เดียวกันกลับมาเสมอก็จริง แต่เราจะต้องเรียกใช้งานผ่าน EventBoss.GetDetadeurus() เท่านั้น ... แล้วมันจะเกิดอะไรขึ้นถ้ามีคนอื่นดันไปสร้าง object นั้นขึ้นมาตรงๆด้วยคำสั่ง new กันล่ะ ?

var myboss1 = new Detardeurus();
var myboss2 = new Detardeurus();

Console.WriteLine(myboss1 == myboss2);

ผลลัพท์ False

เพียงแค่โค้ดด้านบนก็จะทำให้มันมีบอสแบบนี้เกิดขึ้นมาใหม่ 2 object แล้วยังไงล่ะ ดังนั้นโค้ดด้านบนเลยไม่สามารถตอบโจทย์เราได้อย่างแท้จริงนั่นเอง

🧒 แก้โจทย์ครั้งที่ 2

🔥 วิเคราะห์ปัญหา

ถ้าเราวิเคราะห์ปัญหาดีๆ สาเหตุที่แท้จริงของปัญหาในตอนนี้คือ ใครอยากสร้าง object นี้ก็สร้างได้เลย เพียงแค่ใช้คำสั่ง new นั่นเอง (เพราะมันคือพื้นฐานของ class)

แต่ถ้าเราลองไล่ลำดับการทำงานของ class จริงๆเราจะพบว่า เมื่อใช้คำสั่ง new ปุ๊ป สิ่งแรกที่มันจะทำก็คือ มันจะเรียกใช้ Constructor เป็นลำดับแรก ซึ่งโดยปรกติ default constructor จะเป็น public นั่นเอง เลยทำให้ใครอยากสร้าง object ก็สามารถสร้างได้เลย ตามรูป

ดังนั้นเพื่อแก้ปัญหาไม่ให้คนอื่นมาสร้าง object ได้เองมั่วซั่ว เราก็จะทำการ เปลี่ยน Constructor ให้เป็น private ซะ เพียงเท่านี้เราก็จะไม่สามารถใช้คำสั่ง new ในการสร้าง object จากคลาสนี้ได้แล้วนั่นเอง ตามรูปเบย

public class Detardeurus
{
    private Detardeurus()
    {
    }
}

ไม่เชื่อลองไปเขียนโค้ดดูดิ มันจะสร้าง object จากคลาสนั้นไม่ได้เลย

new Detardeurus(); // ERROR

เพียงแค่นี้ก็ไม่มีคนสร้าง object จากคลาสพิเศษของเราได้ละ ... แต่ก็เกิดคำถามใหม่ว่า ถ้าใช้คำสั่ง new สร้าง object ไม่ได้ แล้วเราจะเอา object ของมันออกมาได้ยังไงกันล่ะ ?

🔥 แก้ไขปัญหา

เมื่อเราคิดต่อดูอีกที การที่เราเปลี่ยน constructor เป็น private มันจะทำให้ภายนอกไม่สามารถเข้าถึงได้ แต่ว่า ภายในยังสามารถเข้าถึงได้ตามปรกติ นั่นเอง

ดังนั้นเราก็จะสร้าง object มันจากภายในคลาสมันเองยังไงล่ะ!! ตามรูปเลย อะชึบอะชึบ

public class Detardeurus
{
    private Detardeurus instance;

    private Detardeurus()
    {
        instance = new Detardeurus();
    }
}

เห็นไหมว่าภายในก็ยังใช้งาน constructor ตัวเองได้ตามปรกติ ดังนั้นก็จะเหลือแค่ จะให้ภายนอกเข้ามาใช้งาน object ยังไงนั่นเอง ... ซึ่งตรงนี้มันก็ไม่ยากอีกต่อไป เพราะในโค้ดแรกสุดที่เราออกแบบไว้นั้นทำไว้เรียบร้อยแล้ว โดยการเปิดให้ภายนอกเข้าถึงได้ผ่าน static member นั่นเอง ดังนั้นเราก็จะได้โค้ดออกมาเป็นแบบนี้

public class Detardeurus
{
    private static Detardeurus instance;

    private Detardeurus()
    {
        instance = new Detardeurus();
    }

    public static Detardeurus GetInstance()
    {
        return instance;
    }
}

จบเรียบร้อยแล้ว เพียงเท่านี้เราก็จะได้คลาสพิเศษที่ทั้งโปรแกรมของเรามี object ได้เพียง 1 ตัวเท่านั้น (เพราะภายนอกมันสร้าง object ตัวนี้ไม่ได้) แถมยังมีช่องทางให้เข้าถึงได้จากทุกที่อีกด้วย (ผ่านทาง static นั่นเอง)

🤔 Singleton คือไย ?

🔥 จุดกำเหนิด

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

🔥 ผลจากการใช้

เราสามารถจำกัดการสร้าง object ได้ตามที่เราต้องการ และมีช่องทางเข้าถึงแบบเจ้า object พวกนั้นแบบ Global

🔥 วิธีการใช้

ถ้าเราอยากให้คลาสไหนถูกจำกัดจำนวนในการสร้าง object เราก็แค่ ห้ามให้คนอื่นสร้าง object ได้ตามใจด้วยการทำให้คลาสนั้นเป็น private constructor ซะ ส่วนเงื่อนไขและการสร้าง object ตัวนั้นก็จะถูกจัดการอยู่ภายในคลาสตัวนั้นเอง และเปิดช่องทางให้คนอื่นเข้าถึงผ่าน static member ... เพียงแค่นี้เราก็จะได้คลาสที่เป็น Singleton เรียบร้อยแบ้ว

ไหนลองเอาที่เราออกแบบมาเทียบกันดูดิ๊ ... เหมือนกันเปี๊ยบเบย

🤠 เทคนิค

วิธีการนำ Singleton ไปใช้นั้นมีหลายแบบเลย ซึ่งแต่ละแบบก็จะมีข้อดีข้อเสียที่ต่างกันด้วย ดังนั้นเราลองมาดูกันหน่อยว่ามันมีอะไรกันบ้าง

🔥 Lazy Initialization

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

public class Singleton
{
    private static Singleton instance;

    private Singleton() { }

    public static Singleton GetInstance()
    {
        if (instance == null)
        {
            instance = new Singleton();
        }
        return instance;
    }
}

ซึ่งจากโค้ดจะเห็นว่า ถ้าไม่เคยมีใครเรียกใช้เมธอด GetInstance() นั่นก็หมายความว่า object ตัวนี้ก็จะไม่เคยถูกสร้างเลยนั่นเอง และ ถ้ามันเคยถูกสร้างแล้ว มันก็จะไม่ต้องไปสร้างใหม่อีกเลย

👍 ข้อดี

  • ไม่เสียเวลาในการสร้าง

  • ไม่เปลือง memory

👎 ข้อเสีย

  • ตอนจะสร้างถ้ามันต้องไปทำงานนั่นนู่นนี่เยอะ มันจะทำให้โปรแกรมดูหน่วงๆหน่อยนึง จนกว่าจะสร้างเสร็จ

  • มีปัญหากับการทำงานแบบ Multi-Threading เพราะมันมีโอกาสเข้าไปสร้าง instance พร้อมกัน

🔥 Early Initialization

เป็นด้านตรงกันข้ามกับ Lazy Initialization เพราะมันจะสร้าง object ทิ้งไว้เลยตั้งแต่แรก ซึ่งเป็นโค้ดตามตัวอย่างแรกๆที่เราเขียนไว้ด้านบนเลย

public class Singleton
{
    private static Singleton instance = new Singleton();

    public static Singleton GetInstance()
    {
        return instance;
    }

    private Singleton() { }
}

👍 ข้อดี

  • หลังจากที่มันสร้างเสร็จมันจะพร้อมใช้งานทันที ดังนั้นตอนที่ถูกเรียกใช้ มันจะไม่รู้สึกหน่วงๆ

  • ไม่มีปัญหากับ Multi-Threading

👎 ข้อเสีย

  • เสียเวลาในการสร้าง (ไปหน่วงตอนเปิดแอพแทน)

  • เปลือง memory เพราะ object นั้นอาจไม่เคยถูกเรียกใช้เลยก็ได้ แต่มันถูกสร้างไว้แล้ว

🔥 Bindable Object

โดยปรกติเวลาที่เราทำงานร่วมกับ object ที่มีการเรียกเอาไปใช้งานนั้น เราจะไม่ค่อยสร้างเป็นเมธอดสักเท่าไหร่ เพราะมันเอาไปใช้ในการทำ Data Binding ไม่ได้ (เช่นพวก MVC, MVVM) ดังนั้นเพื่อเป็นการแก้ปัญหาเราจะนิยมไปสร้างเป็น Property มากกว่านั่นเอง

public class Singleton
{
    private static Singleton instance;

    public static Singleton Instance
        => instance;

    protected Singleton()
    {
        instance = new Singleton();
    }
}

👍 ข้อดี

  • นำไปใช้ในการ Binding ได้เลย (1-2 ways ได้หมด)

👎 ข้อเสีย

  • บางภาษาอาจจะไม่เหมาะสมทางเทคนิค

🥴 ข้อผิดพลาดที่เจอบ่อยๆ

⛔ ใช้ static class แทน

การใช้ static class แทนการทำ Singleton pattern นั้นจริงๆก็สามารถทำได้นะ ถ้าเราสามารถคุมการทำงานมันได้ แต่มันจะง่ายกว่าไหมเพียงแค่เปลี่ยนมันเป็น Singleton Pattern แล้วดูแลมันเป็น object ธรรมดาไปเลย ?

⛔ ไม่ใช้ private constructor

ถ้ามาคิดถึง Access Modifier จริงๆแล้วก็มีอีกหลายตัวนะที่ใช้แทน private ได้ เช่น protected (internal ยังไม่สมควรเพราะมันถูกสร้างได้จาก internal namespace นั่นเอง) แต่ถามว่ามันสมควรใช้ของพวกนั้นแทน private ไหม คำตอบคือไม่สมควร เพราะเรามีความตั้งใจที่อยากจะให้มันถูกควบคุมดูแลได้จากที่เดียวอยู่แล้ว ดังนั้นมันไม่ควรมีที่ไหนเข้ามาแก้ไขได้นอกจากตัวเองอีก + การทำ sub class จาก singleton จะมีปัญหาอื่นๆตามมาอีก

🎯 บทสรุป

👍 ข้อดี

  • ช่วยให้เราสามารถควบคุมการสร้าง object ได้

  • มีช่องทางให้เข้าถึงแบบ Global

  • ซ่อนความวุ่นวายในการสร้าง object

  • ถ้าการสร้าง object มีการเปลี่ยนแปลง ก็สามารถแก้ได้จากจุดเดียว

👎 ข้อเสีย

  • ยากต่อการจัดการกับ Life cycle ของมัน

  • มีปัญหากับการเขียนเทส

  • มีปัญหากับ Multi-Threading ถ้าไม่จัดการให้ดี

🤙 ทางเลือก

เราสามารถนำ Framework พวก Dependency Injection (DI) เข้ามาใช้แทนได้นะจ๊ะ โค้ดกระชับหลับสบายเต็มตื่นด้วย

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

แนะนำให้อ่าน สำหรับใครที่ลืมหรืออยากทบทวนการทำงานของ Class & Constructor ก็สามารถเข้าไปดูได้จากลิงค์ตัวนี้เลยครัช

เกลียด ชอบ ถูกใจ อยากติดตาม อยากติชมแนะนำด่าทอ หรืออะไรก็แล้วแต่ (ห้ามมายืมเงิน) จิ้มลงมาที่เพจนี้ได้เลย และจะเป็นประคุณอันล้นพ้นถ้ากด Like + Follow + Share ให้ด้วยขอรับ น้ำตาจิไหล 🥺

👦
🤰
มารู้จักกับ Constructor กันบ้าง
Mr.Saladpuk
Creational Patterns
👦 Design Patterns
ผู้เล่นทุกคนเข้ามาดูได้ว่าสุขภาพของบอสเป็นยังไง ใกล้ถึงเวลาเกิดหรือยัง