《面向对象的艺术》之“设计只允许创建一个对象的类”

说明:

 

我正在撰写《面向对象的艺术——.NET Framework 4.0技术剖析与应用》(暂名)一书,会陆续将一些章节发到我的博客上。

 

作者本人拥有所有的版权。允许自由阅读和转载这些文章,但任何个人与机构不能将其用于商业目的。

补充说明:

 

我在CSDN博客及下载频道发布技术文章与相应教学资源,是长期的一贯的,其目的为推动普及软件技术知识。

 

非常欢迎网友指出我发布的文章中的疏漏,并对我的写作给出中肯与具体的建议,这也是我发布这些文章和资源的目的之一。

 

然而,对于那些主观臆断的,无中生有的,纯粹灌水甚至带有人身攻击的回复,那就免了罢。请这些闲人另找别处发泄去,我这不欢迎你们。 

 

                                 金旭亮

==================================================

 

 

 

《面向对象的艺术》 之

设计只允许创建一个对象的类

   

   对象是以类为模板创建的实例,默认情况下,一个类可以创建无数个对象。

 

       现在问题来了:如果我想限制某个类最多只能创建一个对象,那该怎么办?

       这有N种方式可以实现。本节示例解决方案为OnlyYou,包容几个控制台应用程序。

 

1 “检测对象变量是否为空引用”的方式

       如果我们在创建对象前先检查一下用于引用对象的对象变量是否为空引用,就可限制对象的创建个数(参见示例项目OnlyYou1)。

 

       示例项目中,OnlyYou是一个只允许创建一个对象的类。

 

    class OnlyYou    

    {

}

 

       Program类中定义一个静态字段和静态方法:

 

      static OnlyYou OnlyYouObject = null; //用于引用OnlyYou对象

        //创建OnlyYou对象,只保证创建一个

        static OnlyYou GetOnlyYouObject()

        {

            if (OnlyYouObject == null)

                OnlyYouObject=new OnlyYou();

           return OnlyYouObject;

        }

 

       静态方法GetOnlyYouObject()保证了在整个项目中只能创建一个OnlyYou对象。

 

       以下是放置在Main()中的测试代码。

 

        static void Main(string[] args)

        {

            OnlyYou One, Two;

            One = GetOnlyYouObject();

            Two = GetOnlyYouObject();

            //检查一下两个对象变量是否引用同一对象

            Console.WriteLine(One == Two); //true

        }

    }

 

2 “静态对象计数器”方式

 

       上述“检测对象变量是否为空引用”虽然可以保证整个项目中只能创建一个OnlyYou的对象,但是这种方式必须要在OnlyYou类的外部书写代码,并不方便。

 

       另一种更好的方式是在OnlyYou类的内部设置一个对象计数器,通过检查此计数器的值来确定是否要新建一个对象。

 

       以下是修改过的OnlyYou代码:

 

    class OnlyYou

    {

       private static int ObjectCounter = 0;//对象计数器

       private static OnlyYou OnlyYouObject = null;

 

       public static OnlyYou GetOnlyYouObject()

        {

            if (ObjectCounter == 0)

            {

                OnlyYouObject = new OnlyYou();

                ObjectCounter++;

            }

            return OnlyYouObject;

        }

    }

 

       外界使用OnlyYou.GetOnlyYouObject()方法获取创建的唯一对象的引用。

 

       这个方法看上去不错,但还是有点问题,那就是OnlyYou的使用者完全可以绕开OnlyYou.GetOnlyYouObject()方法,直接使用new关键字创建NOnlyYou对象。

 

 

   解决方法还是有的,这就是将类的构造函数私有化

 

 

3“类的构造函数私有化”方式

       当一个类的构造函数设置为private之后,外界将无法使用new关键字来创建这个类的对象。

 

       修改后的OnlyYou类:

      

    class OnlyYou

    {

        //构造函数私有,外界不能用new直接创建对象

        private OnlyYou()

        {

        }

        //用于保存“独生子”的静态对象变量

        private static OnlyYou OnlyYouObject = null;

        public static  OnlyYou GetOnlyYouObject ()

        {

            if (OnlyYouObject == null) //对象未创建,则创建对象

                OnlyYouObject =new OnlyYou ();

            //向外界返回已创建对象的引用

            return obj;

        }

    }

 

    OnlyYou的关键在于两点:

       1)构造函数私有,则外界无法用new关键字直接创建对象;

       2)提供一个公有静态方法向外界返回已创建对象的引用。

 

提示:

       示例项目OnlyYou的设计方案其实是一种经典的设计模式,名为Singleton(中文译名为“单件”)。设计模式是对一些软件精巧设计方案的总结,设计模式理论是面向对象理论的重要组成部分之一。感兴趣的读者可以去读一本经典的设计模式书籍——《设计模式:可复用面向对象软件的基础》,Erich Gamma 等四名博士所著。

 

4 是否一切真的那么完美?

       应用Singleton设计模式的OnlyYou看上去很不错,它完美地实现了“只能创建一个对象”的预期目标。

 

       然而,这其中还是有陷阱的。那就是我们还没有考虑到多线程的问题。

 

       当有多个线程同时调用OnlyYou.GetOnlyYouObject()方法时,由于Windows操作系统采用抢先式线程调度策略,完全有可能一个线程还未执行完OnlyYou.GetOnlyYouObject()方法就被剥夺了CPU,如果它这时刚刚完成new OnlyYou()的工作,还未来得及更新OnlyYouObject变量,而另一个投入运行的线程在执行OnlyYou.GetOnlyYouObject()方法时会发现OnlyYouObject==null,这将导致一个新的OnlyYou对象被创建。

 

       由于可能发现这种情况,我们就说OnlyYou类不是“线程安全(thread safe)”的。

 

       知道了问题所在,解决起来就比较简单了:

 

class OnlyYou

    {

        //构造函数私有,外界不能用new直接创建对象

        private OnlyYou()

        {

        }

        //用于保存“独生子”的静态对象变量

        private static OnlyYou OnlyYouObject = null;

        public static OnlyYou GetOnlyYouObject()

        {

            lock(typeof(OnlyYou)) //锁定整个类型

            {

            if (OnlyYouObject == null) //对象未创建,则创建对象

                OnlyYouObject=new OnlyYou ();

            //向外界返回已创建对象的引用

            return OnlyYouObject;

            }

        }

    }

 

       通过锁定OnlyYou类型,实现了多线程环境下的OnlyYou.GetOnlyYouObject()方法串行执行。

 

提示:

       在我们这个例子中,由于OnlyYou中只有一个静态方法,也没有任何的公有实例方法,因此,锁定整个类型问题不大。

       然而,如果某个类中包容了多个静态和实例方法,而这个类又频繁地被多个线程访问,则锁定整个类型将有可能带来严重的性能损失,因为所有对此类方法的调用都必须串行执行。

       解决方法是“提供专用的用于线程同步的对象或类型”。

       例如,可以定义一个“没什么用的”类型专用于线程同步:

 

    class UseOnlyForLock

    {

    }

 

       在需要线程同步的地方这样调用:

 

    lock(typeof(UseOnlyForLock))

    {

          //线程同步代码……

    }

      

       这个方法多用于多线程同步静态方法。

       在包容多个方法的类内部,还可以临时增加专用于同步的“没有什么用”的实例成员,专用于多线程同步实例方法:

 

    class SomeClass

    {

        private object SyncObject=new object();

        void SomeMethod()

        {

            lock(SyncObject)

            {

                //线程同步代码……

            }

        }

    }

 

       综合应用上述两种方法,可以有效地避免锁定一个“拥有很多方法和属性”的类型所带来的性能损失。

 

试一试:

       如果我想定义一个可以在运行时“动态”指定创建对象个数的类,应该怎么设计?

 

 

 

  • 0
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 44
    评论
园丁浏览器是一款专门为教师开发的专用软件软件不用注册,最高权限账号:系统管理员 初始密码:000 功能特点简介:软件不用注册,最高权限账号:系统管理员 初始密码:000 1、《安全性》:个人通讯录,证件信息,获奖情况以本地数据库方式保存,且必须有密码才能使用。 2、《在校生证明》:全自动打印,可单张,可批量自动打印,泡茶。。。安心取证! 3、《常用办公软件》:便捷打开。浏览器也是一个软件,WORD、  EXCEL、 PPT、 我的电脑可直接打开,不需要再切换,让您的桌面的这些WORD等图标清除掉,提高开机运行速度。 4、《教育网收录》:厦门教育网、人事网、招生考试。。。便捷打开! (集区教育局,进修学校的网址不稳定,稳定后下个版本会添加上) 5、《专用网站工具》:拒绝广告与网页病毒。提供大量常用工具查询:万年历、歇后语、天气预报、快递查询、邮编查询、地图查询、身份证号码查询。。。完全满足日常需要。 6、《文字排版工具》:有没有经历过在网页上复制文字到WORD时,WORD停止不动,等了N久。。。结果,郁闷,WORD得到的是乱码?? 这个工具,可以清除这些问题!还附带计算字数,自动简单排版。。。 7、《便捷在线音乐》:酷我、百度随身听和一听,不需要查找,不需要百度搜索,便捷打开音乐名站,想听就听! 8、《搜罗网购电商名站》:快捷,随时可用,不需要收藏夹。有淘宝、拍拍。。。 收录了作者常用的网上的一个“就爱折”网!“即时更新集合淘宝和拍拍网促销打折信息的平台网站” 交易是在淘宝和拍拍,无安全隐患。 9、《园丁社区》:可开通片区教研(比如灌口片区)、班级家长交流区、作文参考、论文资源、教案案例。。等等,这些将陆续集合精选教学与学生学习资源。有教学专属的自留地。 10、《我的文档》:我的功课表、记事计划、证件信息、获奖信息。 11、《班主任管理》:暂时提供期末要用的《成绩总表》。项目有:自动生成成绩总表各率,同时自动生成各单科成绩表。 12、WORD修复:经常有WORD使用过程出错,打不开WORD软件,本功能提供修复。 13、EXCEL宏毒清理:运用很简单的办法,清理WINXP系统下的宏程序。 14、基层报表312自动生成:不再需要班主任和教务主任那么辛苦的去分析统计每个年班中,每个性别每个年龄阶段有多少人,有多少个少数民族。。。  这些全自动生成,傻瓜化的导入花名册,就要以泡茶再数据填报! (因为涉及学生太多信息,安全措施为:数据在本地,而且有加密U盘机制,不怕泄漏) 15、《文化户口册数据五大表统计》:仅需手工判断就读区域,其它五大表数据全自动生成! 16、《我的电脑》可以软件中管理我的电脑,不需要切换到桌面,同时,支持不用打开WORD EXCEL 文件就能预览开头材料,选定后再打开。省切找资料时一个一个打开的麻烦。 17、《安全维护》(需要账号,他人用不了): 有数据备份与恢复功能; 清除所有数据功能; 删除EXCLE花名册; 18、办公中心: 1)校历表、办公材料(分有通知管理、职称文件、教学工作、德育工作、班主任、安全、师资等等,为您整合有序的业务材料管理) 2)个人中心:细化获奖情况(论文、指导学生及综合) 3)整合资源,增加我的助手。 4)增加网络收藏夹,让您在校在家,及出差在外,都可共享自己的收藏夹。
评论 44
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值