MicroHelper.Net

雷锋说.对待朋友要MicroHelper,对待敌人要害尔扑
随笔 - 74, 评论 - 431, 引用 - 7

导航

关于

邮件系统不稳定,使用songdming at 263 dot net吧
PageRank

FastCounter by bCentral

 

标签

每月存档

最新留言

  • re: 代码组织
    <a href="http://www.vgoldseller.com/runescape-c-599.html">runescape money</a> ...
    by cxb000(匿名) on 2008/3/26 10:32:11
  • 回复: 看PPMM
    <a target="_new" href="http://www.bestgoldlion.com">http://www.bestgoldlio...
    by runescape gold(匿名) on 2007/12/18 5:13:00
  • 回复: IoC初阶
    <a target="_new" href="http://www.bestgoldlion.com">http://www.bestgoldlio...
    by runescape gold(匿名) on 2007/12/18 5:12:00
  • 回复: 数据分页 (最后更新2003/11/18)
    <a target="_new" href="http://www.sky361.com">http://www.sky361.com</a&...
    by wow power leveling(匿名) on 2007/12/18 5:06:00
  • 回复: iBATIS.Net
    <a target="_new" href="http://www.rsgold-rsgold.com">http://www.rsgold-rsg...
    by runescape money(匿名) on 2007/12/18 5:04:00
  • 回复: 防范Sql注入式攻击
    <a target="_new" href="http://www.rsgold-rsgold.com">http://www.rsgold-rsg...
    by runescape money(匿名) on 2007/12/18 5:03:00
  • 回复: TDD——NUnit的原理
    <a target="_new" href="http://www.rsgold-rsgold.com">http://www.rsgold-rsg...
    by runescape money(匿名) on 2007/12/18 5:03:00
  • 回复: 开源的CMS
    <a target="_new" href="http://www.rsgold-rsgold.com">http://www.rsgold-rsg...
    by runescape money(匿名) on 2007/12/18 5:03:00
  • 回复: CCNet 1.0即将发布
    <a target="_new" href="http://www.sky361.com">http://www.sky361.com</a&...
    by runescape gold(匿名) on 2007/12/18 5:00:00
  • 回复: 关于加班
    为什么这年头加班都成了是我们 的义务了?加班不给加班费也就算了,难得早点回去,还要说三道四的,这社会会为什么会发展成这样啊????
    by 小小(匿名) on 2007/12/14 8:18:00
  • 回复: Presentation草稿:面向对象设计的基本原则
    是的,模式要实事求是,应该是解决问题为主 <br>我搜集了原则方面的文章,有空去看看吧 <br><a target="_new" href="...
    by objecttutor(匿名) on 2007/10/31 17:26:00
  • 回复: 开源的CMS
    支持一下
    by qingxingmeng(匿名) on 2007/10/30 18:03:00
  • 回复: .Net的开源项目
    AnyView(网络警)网络监控软件是一款国内目前最专业的企业级的网络监控软件产品。包含局域网上网监控、邮件监控、聊天监控、BT禁止、流量监视、上下行分离流量限制、并发连接数限制、屏幕监视和录象、硬件...
    by 网络监控软件(匿名) on 2007/10/30 12:33:00
  • 回复: .Net的开源项目
    AnyView(网络警)网络监控软件是一款国内目前最专业的企业级的网络监控软件产品。包含局域网上网监控、邮件监控、聊天监控、BT禁止、流量监视、上下行分离流量限制、并发连接数限制、屏幕监视和录象、硬件...
    by 网络监控软件(匿名) on 2007/10/30 12:32:00
  • 回复: 看PPMM
    好看就成 <br>
    by 11(匿名) on 2007/10/27 15:43:00

广告

 

单例模式

 

使用对象时最基本的事情就是要首先创建对象的实例,一般情况下,这是一件极其简单的事情,就是用new运算符来创建某个对象的实例,简单的人们都不想提及。然而有时候你会发现创建对象的实例也不是那么简单。

 

比如有一些类,在整个程序运行期间只允许一个实例,或者我们说如果有多个实例存在程序逻辑会变得难以控制,很可能遭遇错误,比如对程序所需要的资源如连接池之类的做集中管理。

 

或者从逻辑上讲,在整个程序运行期间可以只有一个实例,当然也可以创建多个实例,这对程序逻辑没有影响,但是实施强制单一对象实例的代价要远低于带来的收益。

 

全部强制对象单一机制有些多余,我们要比较实施强制措施的代价,而不同的实施方案代价和收益是不同的。

 

最原始方案的就是全局变量,程序开始运行时初始化这个全局变量,代码中每一个使用该类的地方都引用这个全局变量。

 

全局变量一个缺点是有些对象实例实际上很可能根本不会用到,而初始化又恰恰要花点时间。没有办法做到延迟加载,当然有聪明的人会说一样可以实现延迟加载,设置一个函数,每次通过这个函数来获得这个全局变量的引用,在函数里面会判断该全局变量的状态,如果没有初始化才作初始化的动作。实际上根本的缺点在于当这样的情况变得越来越多的时候,逻辑变得很复杂,代码变得难以控制,职责变得很不明确。

 

那么我们开始重构,将类的单一实例以及类初始化的职责封装起来,然后提供一个全局的访问点让其他的代码能够访问到这个单一的类的实例。简单的实现方式可能如下:

public sealed class Singleton

{

        static Singleton instance = null;

        private Singleton () {}

        public static Singleton Instance()

        {

                if (instance==null) {instance = new Singleton (); }

                return instance;

        }

}

 

这里把Singleton类的构造函数设置为private是为了其他类不能直接用new方法来创建多个Singleton的实例并使用它,而是提供了一个全局的访问接口Instance()方法,其他的代码只能通过访问Instance方法来获得一个Singleton类的实例。在Instance()中会判断instance是否已经创建,如果没有创建的话才去创建一个实例出来。

 

练习题:为什么instance要声明为static类型的变量。

 

简单测试之后发现可以Singleton类这样的设计实现了我们的意图,那么我们再检查Singleton的代码

如果多个线程同时调用Instance()方法,而这时instance还没有被创建,这时会怎么样呢,怎样保持线程同步?

 

我们可以对Singleton做一点改造,用lock来强制线程同步

public sealed class SingletonLock

{

    static SingletonLock instance=null;

    static readonly object padlock = new object();        

    private SingletonLock() {}

    public static SingletonLock Instance()

    {

        lock (padlock)

        {

            if (instance==null) {instance = new SingletonLock();}

            return instance;

        }

    }

}

 

每次强制线程同步是很耗费资源的,而实际上只有第一次访问Instance()才需要强制线程同步以确保只创建一个实例,那么可以在锁定线程之前先判断instance是否为null,如果为null才调用lock锁定线程。

public static SingletonLock Instance()

{

    if(instance==null)

    {

        lock (padlock)

        {

            if (instance==null)

            {

                instance = new SingletonLock();

            }

        }

    }

return instance;

}

 

javac#Singleton模式提供了天然的支持,于是我们有了更简单的实现方法。

public class Singleton

{

private static Singleton instance = new Singleton();

    private Singleton(){}

    public static Singleton Instance()

    { return instance; }

}

 

static Singleton instancestatic关键字确保instance在被载入AppDomain时被初始化,而且不会有多线程的困扰。这样在访问Instance()方法时,instance必定是已经创建好的,这样的代价就是失去了延迟加载的特性。

应该是the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class.

 

应用Singleton模式会有哪些代价呢,首先实现Singleton模式类的Singleton特性不能被子类天然继承,因为私有变量instance和公共方法Instance()都是静态的,而且基类的构造函数是private的。另外一点就是不透明,调用者知道自己在使用一个Singleton类,需要通过Instance()方法来获得实例。

 

《敏捷软件开发 原则、模式与实践》中介绍了Monostate模式,Monostate模式使用静态变量来实现多个实例共享数据,这样多个类的实例使用起来像一个实例一样,Monostate的代价一方面在于多次创建对象并且销毁会有性能方面的损失,一方面将一个类改造成遵循Monostate模式的类比较麻烦。

 

Singleton强制结构单一,防止创造出多个对象实例,Monostate强制行为单一,所有的实例表现得像一个对象。

 

练习题:

1

以前论坛经常有人争论全是静态函数的Library和遵循Singleton模式的Library孰优孰劣,静态函数的Library有什么缺点?

 

2

CreateSingleton()instance.GetResource()的返回值分别是什么

 

public sealed class Singleton

{

        static Singleton instance = null;

        private int sequence = 0;

 

        private Singleton()

        {

        }

 

        public static Singleton Instance()

        {

                if (instance==null)

                {

                        instance = Initialize();

                }

                return instance;

        }

 

        public int GetResource()

        {

                CreateSequence();

                return sequence;

        }

 

        private static Singleton Initialize()

        {

                System.Threading.Thread.Sleep(200);

                return new Singleton();

        }

 

        private void CreateSequence()

        {

                sequence = sequence + 1;

        }

}

 

public void TestSingleton ()

{

        ThreadPool.QueueUserWorkItem(new WaitCallback(CreateSingleton));

        ThreadPool.QueueUserWorkItem(new WaitCallback(CreateSingleton));

}

 

public void CreateSingleton(object o)

{

        SingletonNotThreadSafeConsuming instance = SingletonNotThreadSafeConsuming.Instance();

        instance.GetResource();

}

打印 | 张贴于 2005-09-13 19:02:00 | Tag:Dot Net  拥抱变化

留言反馈

#回复: Design.Patterns.Step.By.Step.3 编辑
大家都知道,一般我们用DirectoryEntry这个类来操作AD对象。

DirectoryEntry类的构造函数通过指定Path就可以绑定到DC。例如,我们常用的LDAP:
2006-12-28 08:50:00 | [匿名:我考百试通]
#问题2 编辑
1,1还是1,2?
2005-09-14 19:01:00 | [匿名:Kane]
#re: Design.Patterns.Step.By.Step.3 编辑
静态函数的Library和遵循Singleton模式的Library

也存在着疑问,
能帮忙解释一下各自的优缺点吗,
2005-09-14 09:20:00 | [匿名:feelwindy]
#re: Design.Patterns.Step.By.Step.3 编辑
我只想到static library的优点:

如果都是一些utility functions, 没有状态需要保持, 或者状态可以由client通过参数传递,那么静态函数的library比较好。特别是在C++中, 由于没有GC, 一个singleton的释放问题很头痛。

Singleton模式的library的好处上可以在整个程序运行过程中保持一些数据,如单个实例数据, 状态信息等,不过如果是多线程的话可能还要提供锁定。如果本身并没有singleton的语义要求, 最好不要这样作。特别是在library的层次上。
2005-09-14 09:20:00 | [匿名:问题]
#re: Design.Patterns.Step.By.Step.3 编辑
double checked locking 在Java中并不是多线程安全的,C++没有定义, 要看生成的汇编代码。 C#不了解。
2005-09-14 09:08:00 | [匿名:问题]
#re: Design.Patterns.Step.By.Step.3 编辑
@Richard Lee

你是对的,静态fields是在第一次访问该类型时创建的,并且保证AppDomain中只存在一份。
2005-09-13 22:13:00 | [匿名:Microhelper]
#re: Design.Patterns.Step.By.Step.3 编辑
还有就是,在C#里面使用private static Singleton instance = new Singleton(); 这样的情况一样是在第一次使用到Singleton类型的时候才执行构造函数的,并不是在AppDomain加载时。
2005-09-13 21:58:00 | [匿名:Richard Lee]
#re: Design.Patterns.Step.By.Step.3 编辑
似乎,java里面用
public class Singleton

{

private static Singleton instance = new Singleton();

private Singleton(){}

public static Singleton Instance()

{ return instance; }

}这样的方式,
多线程并发是还是可能会导致实例被创建多次。
不过我一直没有遇到过这样的情况出现。
2005-09-13 21:45:00 | [匿名:Richard Lee]
对不起,目前本随笔不允许发表新评论.

Powered by: Joycode.MVC引擎 0.5.2.0