<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged designpattern</title>
<link>https://coderlegion.com/tag/designpattern</link>
<description>Powered by Question2Answer</description>
<item>
<title>A Finite State of One: Rethinking the Singleton Pattern with FSMs</title>
<link>https://coderlegion.com/7415/a-finite-state-of-one-rethinking-the-singleton-pattern-with-fsms</link>
<description>&lt;h2 id=&quot;a-finite-state-of-one-rethinking-the-singleton-pattern-with-fsms&quot;&gt;A Finite State of One: Rethinking the Singleton Pattern with FSMs&lt;/h2&gt;
&lt;p&gt;The Singleton pattern is a cornerstone of game development and application architecture, ensuring a class has only one instance and providing a global point of access. Yet, its implementation in C# can often feel like wrestling with unnecessary boilerplate—or worse, a forced, inflexible use of generics that clutters your codebase.&lt;/p&gt;
&lt;p&gt;What if your Singleton could be inherently &lt;strong&gt;self-regulating&lt;/strong&gt;, decoupling the enforcement logic from the class itself, all while giving you granular control over performance?&lt;/p&gt;
&lt;p&gt;We recently discovered an incredibly intuitive and versatile approach that achieves just this, leveraging the power of a modern Finite State Machine (FSM) framework, specifically &lt;strong&gt;TheSingularityWorkshop.FSM_API&lt;/strong&gt;, to abstract and enforce the Singleton constraint.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-pain-points-of-traditional-singletons&quot;&gt;The Pain Points of Traditional Singletons&lt;/h3&gt;
&lt;p&gt;Most C# Singletons fall into two camps, both of which introduce either bloat or manual effort:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The Boilerplate (Non-Generic):&lt;/strong&gt; Requires manual static field, private constructor, and thread-safety logic for every class.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Generic (Templated):&lt;/strong&gt; Reduces boilerplate but introduces a base class dependency, which can be seen as &quot;bloat&quot; and often complicates inheritance hierarchies.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here is a quick look at the typical C# Unity implementation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class ClassicInputManager : MonoBehaviour
{
    private static ClassicInputManager _instance;

    public static ClassicInputManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = FindObjectOfType&amp;lt;ClassicInputManager&amp;gt;();
                if (_instance == null)
                {
                    Debug.LogError(&quot;ClassicInputManager not found in scene!&quot;);
                }
            }
            return _instance;
        }
    }

    // Other class members...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is fragile: what if two instances are accidentally placed in the scene? You have to add clumsy boilerplate to &lt;code&gt;Awake()&lt;/code&gt; or &lt;code&gt;Start()&lt;/code&gt; to destroy duplicates, and the instance check runs on every single call to &lt;code&gt;Instance&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-fsm-driven-singleton-self-healing-and-performant&quot;&gt;The FSM-Driven Singleton: Self-Healing and Performant&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;&lt;code&gt;FSM_Singleton&lt;/code&gt;&lt;/strong&gt; is an abstraction layer that wraps your target class (the actual Singleton, like a &lt;code&gt;BuildersInputManager&lt;/code&gt;) and delegates the enforcement of uniqueness to an FSM instance.&lt;/p&gt;
&lt;p&gt;By creating an FSM instance upon the target's initialization, we gain immediate access to the FSM API's core benefits: robust lifecycle management and customizable processing rates.&lt;/p&gt;
&lt;p&gt;In the example below, the &lt;code&gt;BuildersInputManager&lt;/code&gt; simply creates an &lt;code&gt;FSM_Singleton&lt;/code&gt; in its &lt;code&gt;Awake()&lt;/code&gt; method:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class BuildersInputManager : MonoBehaviour, IStateContext
{
    // ...
    void Awake()
    {
        // Establish this as a singleton, checking for duplicates every 10 update calls
        new FSM_Singleton(this, 10, &quot;Update&quot;); 
    }
    // ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The magic lies within the &lt;code&gt;FSM_Singleton&lt;/code&gt;'s constructor and the single &quot;Operating&quot; state of its FSM definition:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class FSM_Singleton : IStateContext
{
    public FSM_Singleton(IStateContext stateContext, int processRate, string processGroup)
    {
        // 1. Create FSM Definition (if it doesn't exist)
        if(!FSM_API.Interaction.Exists(&quot;BuildersInputManager&quot;, processGroup))
        {
            FSM_API.Create.CreateFiniteStateMachine(&quot;BuildersInputManager&quot;, processRate, processGroup)
                .State(&quot;Operating&quot;, null, OnUpdateOperating, null)
                .BuildDefinition();
        }
        // 2. Create FSM Instance for the target context
        Status = FSM_API.Create.CreateInstance(&quot;BuildersInputManager&quot;, this, processGroup);
        // ...
    }

    private void OnUpdateOperating(IStateContext context)
    {
        if(context is FSM_Singleton singleton)
        {
            Enforce(singleton); // Check and remove duplicates
        }
    }

    private void Enforce(FSM_Singleton singleton)
    {
        var bucket = FSM_API.Internal.GetBucket(stateContext.Name, singleton.ProcessGroup);
        if (bucket.Instances.Count &amp;gt; 1)
        {
            RemoveRedundant(singleton, bucket);
        }
    }
    
    private static void RemoveRedundant(FSM_Singleton singleton, FSM_API.Internal.FsmBucket bucket)
    {
        for (int i = bucket.Instances.Count - 1; i &amp;gt;= 0; i--)
        {
            var instanceHandle = bucket.Instances[i];
            if (instanceHandle.Id != singleton.Status.Id)
            {
                Debug.LogWarning($&quot;Destroyed duplicate instance with ID: {instanceHandle.Id}&quot;);
                FSM_API.Interaction.DestroyInstance(instanceHandle);
            }
        }
    }
    // ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;versatility-and-performance-decoupling-enforcement&quot;&gt;Versatility and Performance: Decoupling Enforcement&lt;/h4&gt;
&lt;p&gt;This mechanism showcases the ingenuity of &lt;strong&gt;decoupled architecture&lt;/strong&gt;. Unlike traditional Singleton implementations, where duplicate checks must occur on every static property access or during immediate object instantiation, the &lt;code&gt;FSM_Singleton&lt;/code&gt; establishes a &lt;strong&gt;self-healing contract&lt;/strong&gt;. It initiates a constant, scheduled validation loop to ensure the existence of exactly one instance.&lt;/p&gt;
&lt;p&gt;In the typical and expected scenario, the &lt;code&gt;OnUpdateOperating&lt;/code&gt; logic performs a lightning-fast API call to retrieve the instance count, instantly confirming a count of one, and then terminates its execution for that cycle. This high-performance check effectively minimizes frame-time overhead.&lt;/p&gt;
&lt;p&gt;Crucially, in the rare event that a duplicate is accidentally created, the enforcement logic will instantly &lt;strong&gt;eradicate it&lt;/strong&gt; (&lt;code&gt;DestroyInstance&lt;/code&gt;). This limits the duplicate's lifespan to the number of frames defined by the FSM's &lt;code&gt;ProcessRate&lt;/code&gt;. By setting &lt;code&gt;ProcessRate = 10&lt;/code&gt; (as in the example), we drastically reduce overhead because the resource-intensive cleanup iteration runs only periodically, yet the detection and destruction of a redundant instance is still handled automatically and asynchronously.&lt;/p&gt;
&lt;p&gt;Furthermore, the FSM framework allows for assigning this check to a specific &lt;strong&gt;Processing Group&lt;/strong&gt;, enabling advanced scheduling tactics such as running the validation only during periods of available frame time, thus prioritizing critical game logic.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;analysis-fsm-vs-classic-singleton&quot;&gt;Analysis: FSM vs. Classic Singleton&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;Feature &lt;/th&gt;&lt;th align=&quot;left&quot;&gt;Classic C# Singleton (Standard Boilerplate) &lt;/th&gt;&lt;th align=&quot;left&quot;&gt;FSM_Singleton (TheSingularityWorkshop.FSM_API)&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Enforcement Logic &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Scattered throughout the target class (&lt;code&gt;Awake&lt;/code&gt;/&lt;code&gt;Start&lt;/code&gt; for cleanup, static property for creation/access). &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Centralized and abstracted in the dedicated &lt;code&gt;FSM_Singleton&lt;/code&gt; class.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Duplicate Handling &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Must be manually coded for destruction; highly prone to developer error and race conditions. &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Self-Healing via periodic FSM state updates (&lt;code&gt;OnUpdateOperating&lt;/code&gt;), automatically detecting and destroying duplicates.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Performance &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Enforcement or creation checks typically run every frame or on every public static &lt;code&gt;Instance&lt;/code&gt; access, leading to constant minor overhead. &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Highly Configurable via &lt;code&gt;ProcessRate&lt;/code&gt; (e.g., run every 10th frame, or only on event), significantly minimizing the update overhead.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Code Style &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Requires repetitive boilerplate (static field, private constructor, lock) or forces generic base class inheritance, potentially complicating the object hierarchy. &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Clean pattern implementation without unnecessary generics, relying on standard interfaces (&lt;code&gt;IStateContext&lt;/code&gt;) and a clean API wrapper.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The FSM-based approach successfully elevates the Singleton pattern beyond a rigid architectural constraint, transforming it into a &lt;strong&gt;flexible, self-regulating service&lt;/strong&gt;. This decoupled solution expertly manages its own lifecycle and performance with exceptional granularity, representing a potent abstraction that simplifies the codebase and entirely eliminates the common implementation headaches associated with managing instance uniqueness.&lt;/p&gt;
&lt;p&gt;Resources &amp;amp; Code:&lt;/p&gt;
&lt;p&gt;The FSM Package (Unity Asset Store):&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://assetstore.unity.com/packages/slug/332450&quot;&gt;https://assetstore.unity.com/packages/slug/332450&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;NuGet Package (Non-Unity Core):&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.nuget.org/packages/TheSingularityWorkshop.FSM_API&quot;&gt;https://www.nuget.org/packages/TheSingularityWorkshop.FSM_API&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;GitHub Repository:&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/TrentBest/FSM_API&quot;&gt;https://github.com/TrentBest/FSM_API&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Support Our Work:&lt;/p&gt;
&lt;p&gt;Patreon Page:&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.patreon.com/c/TheSingularityWorkshop&quot;&gt;https://www.patreon.com/c/TheSingularityWorkshop&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; Support Us (PayPal Donation):&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.paypal.com/donate/?hosted_button_id=3Z7263LCQMV9J&quot;&gt;https://www.paypal.com/donate/?hosted_button_id=3Z7263LCQMV9J&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We'd love to hear your thoughts! Please Like this post, Love the code, and Share your feedback in the comments.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=10913738559640252946&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
</description>
<category>C#</category>
<guid isPermaLink="true">https://coderlegion.com/7415/a-finite-state-of-one-rethinking-the-singleton-pattern-with-fsms</guid>
<pubDate>Sun, 16 Nov 2025 06:50:33 +0000</pubDate>
</item>
</channel>
</rss>