代码之家  ›  专栏  ›  技术社区  ›  this. __curious_geek

抽象基类以强制每个派生类为单例

  •  8
  • this. __curious_geek  · 技术社区  · 15 年前

    如何创建一个抽象类来强制每个派生类都是单例的?我用C语言。

    6 回复  |  直到 10 年前
        1
  •  3
  •   Steven    15 年前

    当您想要强制执行编译时检查时,这是不可能的。通过运行时检查,您可以做到这一点。它不漂亮,但它是可能的。下面是一个例子:

    public abstract class Singleton
    {
        private static readonly object locker = new object();
        private static HashSet<object> registeredTypes = new HashSet<object>();
    
        protected Singleton()
        {
            lock (locker)
            {
                if (registeredTypes.Contains(this.GetType()))
                {
                    throw new InvalidOperationException(
                        "Only one instance can ever  be registered.");
                }
                registeredTypes.Add(this.GetType());
            }
        }
    }
    
    public class Repository : Singleton
    {
        public static readonly Repository Instance = new Repository();
    
        private Repository()
        {
        }
    }
    
        2
  •  6
  •   Jack    15 年前

    这将不起作用,因为单例需要一个静态访问,而这是不可强制的。

    有关singletionimplemention+示例,请参见: Implementing the Singleton Pattern in C#

        3
  •  2
  •   Jake    15 年前

    singleton意味着拥有私有的构造函数。但是你知道私人成员不能被继承。在C++中有模板,所以你可以从模板类中创建一个单子。在C中,没有模板,因此您必须为所需的每个单例编写自己的私有构造函数。

        4
  •  2
  •   dan    11 年前

    这是一种(丑陋的)方法。它可能会被简化和改进,但这是我第一次尝试。

    其思想是首先使基类成为通用抽象类(如上面的注释中所述),但类型参数被约束为从基类本身派生。这允许基类处理派生类型的单例实例。注意,所有派生类都应该密封,就像任何单例类一样。

    接下来,允许使用受保护的构造函数,但需要接受一个特殊类singletonkey的实例,该类是一个经过修改的singleton。派生类可以访问singletonkey类定义,但基类保留对唯一允许的实例的私有控制,从而对所有派生对象的构造进行控制。

    第三,基类需要能够调用派生类的构造函数,但这有点棘手。如果您试图调用派生的键化构造函数,编译器会抱怨,因为它不一定存在。解决方案是添加派生类必须初始化的静态委托。因此,任何派生类都需要提供一个简单的初始化方法。在代码中首次尝试访问实例之前,应显式调用此初始化方法,否则将导致运行时错误。

    public abstract class Singleton<T> where T : Singleton<T>
    {
        protected Singleton(SingletonKey key) { }
        private static SingletonKey _key;
        private static SingletonKey Key
        {
            get
            {
                if (_key == null) SingletonKey.Initialize();
                return _key;
            }
        }
        protected class SingletonKey
        {
            private SingletonKey()
            {
            }
            public static void Initialize()
            {
                if (_key == null)
                {
                    _key = new SingletonKey();
                }
            }
        }
    
        protected static Func<SingletonKey, T> Creator;
        private static T instance;
        public static T Instance
        {
            get
            {
                if (instance == null) instance = Creator(Key);
                return instance;
            }
        }
    }
    
    public class MySingleton : Singleton<MySingleton>
    {
        public string Name { get; set; }
        public static void Initialize()
        {
            Creator = (key) => new MySingleton(key);
        }
        protected MySingleton(SingletonKey key) : base(key)
        {
        }
    }
    
        5
  •  1
  •   Community CDub    8 年前

    Java或C语言中的类不是“一流”。类的静态部分不能被子类继承或重写。见 this answer 了解更多详细信息。另外,您没有元类的概念。

    在诸如smalltalk或ruby之类的语言中,您可以定义一个新的元类 Singleton 它定义了一个方法 getInstance . 然后你可以定义 ClassA ClassB 成为 独生子女 元类然后两个类都自动公开一个方法 获取实例 可用于创建实例 objectA objectB . 那不酷吗?实际上,你不经常使用元类,而单例实际上是它们唯一有意义的用法,我知道。

        6
  •  0
  •   Uros Kac    10 年前

    我认为我试图实现类似的功能,即在一组类上强制使用公共接口和单例模式。这是我的解决方案:

    // Common interface of my singleton classes
    public interface IMySingletonClass
    {
        string ValueGetter();
    
        void ValueSetter(string value);
    }
    
    // Generic abstract base class
    public abstract class Singleton<T>: IMySingletonClass
    {
        private static readonly object instanceLock = new object();
        private static T instance; // Derived class instance
    
        // Protected constructor accessible from derived class
        protected Singleton()
        {
        }
    
        // Returns the singleton instance of the derived class
        public static T GetInstance()
        {
            lock (instanceLock)
            {
                if (instance == null)
                {
                    instance = (T)Activator.CreateInstance(typeof(T), true);
                }
                return instance;
            }
        }
    
        // IMySingletonClass interface methods
        public abstract string ValueGetter();
    
        public abstract void ValueSetter(string value);
    }
    
    // Actual singleton class
    public class MySingletonClass : Singleton<MySingletonClass>
    {
        private string myString;
    
        private MySingletonClass()
        {
            myString = "Initial";
        }
    
        public override string ValueGetter()
        {
            return myString;
        }
    
        public override void ValueSetter(string value)
        {
            myString = value;
        }
    }
    

    下面是一个简单的测试:

    class Program
    {
        static void Main(string[] args)
        {
            MySingletonClass r1 = MySingletonClass.GetInstance();
            Console.WriteLine("R1 value = {0}", r1.ValueGetter());
            r1.ValueSetter("Changed through R1");
            MySingletonClass r2 = MySingletonClass.GetInstance();
            Console.WriteLine("R2 value = {0}", r2.ValueGetter());
    
            Console.ReadKey();
        }
    }
    

    请注意,如果您只需要基本的“模板”,那么可以很容易地从泛型抽象单例类中删除公共接口。

    推荐文章