当前位置:编程学习 > C#/ASP.NET >>

实现一个只能实例化一个对象的类(C#)

收听我的腾讯微博吧http://t.qq.com/wuhanbiao
收听我的新浪微博吧http://t.sina.com.cn/hanbiaowu
 
上次峰哥出了一个思考题:实现一个只能实例化一个对象的类(C#)。

 

峰哥言:去写一个只能实例化一个对象的类。就像有些程序只能打开一个,打开第二个的时候,会跳出原来那个或是提示程序在运行?>*&……%

 

我想:

第一个想到的是static,静态存储持续。在C/C++里面,静态持续变量按链接性可分为三种,即外部链接性、内部链接性和无链接性。此处讨论无链接性的静态持续变量,即用static限定符在代码块中定义的局部变量。此变量的特点是,静态存储,虽然变量只在定义它的代码块可用,但它在该代码块不处于活动状态的时候仍然存在于内存之中。因此在两次函数调用之间,静态局部变量的值将保持不变。另外,如果初始化了静态局部变量(只能用常量初始),则程序只在启动时进行一次初始化,之后的函数调用将不会像自动变量(auto)那样再次被初始化。

但是峰哥的提示强调的是将构造函数设为私有的(private)。我想不通,到底该如何处理?

既然构造函数是私有的,那就肯定不能直接通过构造函数来生成对象,而应该用一个公有的(public)成员函数来调用构造函数,而对象都还没有又想要调用成员函数,那么此函数必定是静态的,即下面的StaticConstruct()。第二个问题,当有人想实例化第二个对象的时候,怎么阻止?……阻止很简单,关键是如何判断是第二次还是第一次,那就需要一个静态成员currentInstance。后来,我觉得答案应该是这样的,至少这是一种可行的方案。

 

实现代码:

/// Once.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2011_3_7
{
    class Once
    {
        private string text;
        private string name;
        private DateTime birthday;

        static Once currentInstance = null;

        private Once()
        {
            text = "我只能实例化一个对象哦!";
            name = ">_< 我还没有名字呢!";

            // 记录当前时间,设为生日
            birthday = DateTime.Now;
        }

        ~Once()
        {
            currentInstance = null;
        }

        static public Once StaticConstruct()
        {
            if (null == currentInstance)
            {
                currentInstance = new Once();
            }
            else
            {
                Console.WriteLine("对象已经创建过了哦!");
                //return null;
            }
            //currentInstance = new Once();
            return currentInstance;
        }

        public void ShowMySecret()
        {
            Console.WriteLine("告诉你一个秘密:" + text);
        }

        public void SetMyName(string name)
        {
            this.name = name;
        }

        public void ShowMyName()
        {
            Console.WriteLine("我的名字是:" + name);
        }

        public void ShowMyBirthday()
        {
            Console.WriteLine("我的生日是:" + birthday.ToLongDateString() + birthday.ToLongTimeString() + " " + birthday.Millisecond + "毫秒");
        }
    }
}



测试代码:

/// Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2011_3_7
{
    class Program
    {
        static void Main(string[] args)
        {
            // 实例化第一个对象
            Once instance1 = Once.StaticConstruct();
            instance1.SetMyName("TheSoleInstance");
            instance1.ShowMySecret();
            instance1.ShowMyName();
            instance1.ShowMyBirthday();
            Console.WriteLine();
            
            // 试图实例化第二个对象
            Once instance2 = Once.StaticConstruct();
            instance2.ShowMySecret();
            instance2.ShowMyName();
            instance2.ShowMyBirthday();
            Console.WriteLine();

            // 改变“第二个对象”的名字,再显示第一个对象的名字
            instance2.SetMyName("TheInstance2");
            instance1.ShowMyName();
            Console.WriteLine();

            OutOfMain();
            
            Console.Read();
        }

        static void OutOfMain()
        {
            // 试图实例化第三个对象
            Once instance3 = Once.StaticConstruct();
            instance3.ShowMySecret();
            instance3.ShowMyName();
            instance3.ShowMyBirthday();
            Console.WriteLine();
        }
    }
}

 

运行结果:
[img=http://b204.photo.store.qq.com/http_imgload.cgi?/rurl4_b=3a87d52f114bea68769ef6c5be4edfc7d521103c9c4a34bbd5c2a5594c426fb2d9e999707e0c4fd225449b0873588ff6953c9481c421d784f687fe231d8d6c62e7c074eae71b79b4d6e15a86918ca02669c32cab&a=206&b=204][/img]
分析:生日(构造时间)一样,说明这是同一个对象,而且在更改“第二个对象”的名字,而第一个对象的名字也随之改变,说明它们是同一个对象。
 
若在第二次实例化对象的时候,不返回已有实例的引用,而是返回空,return null。
则效果如下
[img=http://b205.photo.store.qq.com/http_imgload.cgi?/rurl4_b=3a87d52f114bea68769ef6c5be4edfc7689bc75eee54b0e9ac787564e66632841cbde27ee9fbe1b1fc024f3f8e8512a1058fdac521620ad410e9786ea2d1e7307823b07bb011862814f2f170fcad25acd074cf50&a=201&b=205][/img]
为处理的异常。很显然,当instance2为null时,instance2.ShowMySecret();是有问题的。
 
至此,该类已经实现了一次只能实例化一个对象的功能。
 
收听我的腾讯微博吧http://t.qq.com/wuhanbiao
收听我的新浪微博吧http://t.sina.com.cn/hanbiaowu --------------------编程问答-------------------- 单件模式,去看看设计模式吧 --------------------编程问答--------------------

class A
{
   private A(){ }
   
   public static Create() { return new A() }

}


--------------------编程问答--------------------
引用 1 楼 gui0605 的回复:
单件模式,去看看设计模式吧


+1 --------------------编程问答-------------------- 单件模式,注意单线程还是多线程就好.
补充:.NET技术 ,  C#
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,