I don’t know what is this pattern.

最近幾天每天都在寫 C#,寫的是某個自己要用的程式,由於只是自己用的,就只求速成,沒有花太多精神在設計上,直到這兩天才感覺到這樣不行,我實在重複了太多次相同的程式,因此決定改寫。

要描述我的需求太麻煩,直接看 code!我理想中的介面是長這樣:

Console.WriteLine(English.Hello());
Console.WriteLine(Chinese.Hello());
Console.WriteLine(Japanese.Hello());
Console.WriteLine(French.Hello());
  1. 上面的 EnglishChineseJapaneseFrench 都是 subclass,Hello() 是 static method,所以不需要實例就能直接呼叫,呼叫了之後就會回傳各國語言的 Hello。
  2. 同時我希望上述這些 subclass 只要繼承某個 class,就能有一個預設的 Hello(),當有必要時我再 override 這個 method。

起初我是朝 Singleton 的方向研究,由於我想要的是透過繼承,讓 subclass 輕鬆成為 Singleton,所以我應該用 Registry of Singletons。但是我實作出來後,發現我還是得在每個 subclass 複製貼上相同的 code,要不然就是呼叫方式會變成像 English.Instance.Hello() 這般冗贅。有關 C# 如何實做 Registry of Singletons,請參考這篇:The Quest for the Generic Singleton in C#1

我現在實際作出的介面是長這樣:

Console.WriteLine(Say<English>.Hello());
Console.WriteLine(Say<Japanese>.Hello());
Console.WriteLine(Say<Chinese>.Hello());
Console.WriteLine(Say<French>.Hello());

雖然還沒達到理想,但我覺得不錯了。整個實作如下:

namespace Speaking
{
    // 介面
    interface ILanguage
    {
        string Hello();
    }

    // 基底類別,加上 abstract 是為了避免它被實例化
    abstract class DefaultLanguage : ILanguage
    {
        public virtual string Hello()
        {
            return "Hello!";
        }
    }

    // 呼叫用的類別
    static class Say<TLanguage> where TLanguage : ILanguage, new()
    {
        private static TLanguage instance;
        public static TLanguage Language
        {
            get
            {
                // 這裡有點像 Registry of Singletons
                // 但我不需要 Registry 就能管理多個 Singletons
                // 我也覺得很奇妙 XD
                if (instance == null)
                {
                    instance = new TLanguage();
                }
                return instance;
            }
        }

        // 這才是上面範例中呼叫到的 Hello()
        public static string Hello()
        {
            return Language.Hello();
        }
    }

    // 以下是幾個子類別
    class English : DefaultLanguage
    {
        // 一切都照基底類別,所以我什麼都不用寫
        // 附帶一提,這裡不可以寫 private constructor
    }

    class Chinese : DefaultLanguage
    {
        // 繼承基底類別,並且 override
        public override string Hello()
        {
            return "你好!";
        }
    }

    class Japanese : ILanguage
    {
        // 也可以只實作 ILanguage 介面,不繼承基底類別
        public string Hello()
        {
            return "こんにちは!";
        }
    }

    class French : DefaultLanguage, ILanguage
    {
        // 也可以繼承、實作一起來,其實這個跟只有繼承是一樣的
        public override string Hello()
        {
            return "Bonjour!";
        }
    }
}

這個方法有個毛病,那些子類別還是可以建立實例,所以不能保證 Singleton。

// 這樣寫的話,就會產生一個新的 English 物件
ILanguage en = new English();

  1. 這篇文章的標題寫得就像要在 C# 中實作 Singleton 是個天大的謎似的 XD 

1 Comment

  1. 看起來應該是 Singleton + Proxy Pattern,都是很簡單的 Pattern XD

Leave your thoughts
  • You can use some HTML in your comment.
  • Your comment may not display immediately due to spam filtering. Please wait for moderation.