学习Singleton(单一)设计模式

来源:互联网 发布:在淘宝买游戏号安全吗 编辑:程序博客网 时间:2024/06/11 15:00

      1、Singleton模式可以解决什么问题或者说我们使用它的动机是什么?:几乎在每个应用程序中,都需要有一个从中进行全局访问和维护  某种类型数据的区域。在面向对象系统中也有这种情况,在此类系统中,在任何给定时间只应运行一个类或某个类的一组预定义数量  的实例。例如,当使用某个类来维护增量计数器时,此简单的计数器类需要跟踪在多个应用程序领域中使用的整数值。此类需要能够  增加该计数器并返回当前的值。对于这种情况,所需的类行为应该仅使用一个类实例来维护该整数,而不是使用其它类实例来维护该  整数。
   最初,人们可能会试图将计数器类实例只作为静态全局变量来创建。这是一个通用的方法,但实际上只解决一部分问题;他解决  了全局可访问性问题,但没有采取任何措施来确保在任何给定的时间只运行一个类实例。应该由类本身来负责只使用一个类实例,而  不是由类用户来负责。应该始终不要让类用户来监视和控制运行的类实例的数量。
   所需要的是使用某种方法来控制如何创建类实例,然后确保在任何给定的时间只创建一个类实例。这会确切地给我们提供所需的  行为,并使客户端不必了解任何类细节。
      2、Sigleton模式的设计意图是:保证一个类只有一个对象实例,并提供一个访问对象实例的全局访问点。
  如果我们想实现一个全局范围可见的对象以替代麻烦缠身的全局变量,那么,最好的做法是将
数据封装在一个特殊的类中,这个类严格管理数据的创建过程以保证数据的唯一性,同时不允许程序员随意创建该类的对象实例(这可以通过将类的构造函数声明为priate 或protected 类
  型来实现)。虽然不能通过类的构造函数获得对象实例,但可以从该类提供的静态成员函数得
  到该类唯一的对象实例的指针或引用。
 3、Singleton模式和全局变量有什么本质的区别?
 全局变量的问题:
  (1)变量名冲突:必须小心维护变量名规则,所有工程师在开发代码时,每遇到一个全局变量,
  都必须仔细分辨该变量究竟属于哪个模块、哪个程序。
  (2)偶合度难题:全局变量实际上增加了函数与模块之间的耦合度。用通俗的话说,需要访问
  某个特定全局变量的多个函数被该变量牢牢地“粘结”在一起,成为拆不散的一团乱麻。
  (3)单个实体问题:全局变量不能阻止程序员定义一个类的多个对象实例。如果没有其它技术
  手段帮助,保证一个类只有单个实例就全靠程序员的自觉。
  (4)初始化顺序:全局变量不能保证相互之间遵循特定的初始化顺序,这完全由编译器决定。
  对于类的对象实例,构造函数被调用的顺序有时就显得非常重要。
  (5)多线程访问:当多个并发的线程都需要访问某些全局变量时,我们必须使用各种同步机制,
  小心地保护这些全局变量,以免陷入并发冲突的泥潭。
 4、单一类的来源
  使用单一类最容易犯的一个错误就是按照原来结构化程序设计的思路考虑问题,把全局变量作为模块之间共享数据的的一个桥梁,即
 把多个局部变量收集起来,放进一个单件类中,这样是换汤不换药、新瓶装旧酒的做法,它虽然可以减少一些全局变量,部分地解决命名冲突问题,但是对系统的框架却没有任何好处,全局变量本身的风险依然存在。
  面向对象设计和开发技术的主旨是对数据和相关操作的封装。在面向对象理论开来,向全局变量这样可能无限制地增加模块间偶合关
 系的语言要素实在是过时的、危险的和应该抛弃的。在更加纯粹的面向对象语言,如Java 和C#中,我们实际上已经找不到了全局变量的  踪影,甚至连main函数也躲进了类结构内部。在Java和C#语言中,我们可以使用public类型的字段、方法或者属性来实现我们在C语言中  经常要用全局变量实现的功能。
  在系统中提炼单一类的根本方法应当是,在面向对象分析与面向对象设计的基础上,寻找哪些具有单件类的特性、生命周期较长的类 ,把它们改写成单一类的形式。在这样的分析和设计过程中,根本就没有全局变量存活的空间。
 5、基本结构
 
 #include <iostream.
 using namspace std;
 
 class StaticTest
 {
  public :
   void SetVar(int v) { Var=v}
   static void SetSVar(int v) {s_Var=v}
   
   int GetVar(void) {return Var;}
   static int s_GetVar(void) {return Var;}
   
   int GetSVar(void) {return s_Var;}
   static int s_GetSVar(void) {return s_Var;}
  private:
   int Var;
   static int s_Var;
 };
 int main()
 {
  StaticTest t1,t2;
  t1.SetVar(1);
  t1.SetSVar(1);
  t2.SetVar(2);
  t2.SetSVar(2);
  cout<<"t1.Var="<<t1.GetVar()<<endl;
  cout<<"t1.s_Var="<<t1.GetSVar()<<endl;
  cout<<"t2.Var="<<t1.GetVar()<<endl;
  cout<<"t2.Var="<<t1.GetSsVar()<<endl;
  return 0;
  
 }
 
 
 《敏捷软件开发 原则、模式和实践》:
 singleton:
    有一些类,它们应该只有一个实例。这个实例似乎在程序启动时被创建出来的,并且只在程序结束时才被删除。有时,这种对象 是应 用程序的基础对象。通过这些基础对象可以得到系统中的很多其它对象。有时,它们是工厂对象,用来创建系统中的其它对 象,有时 ,这些对象是管理器对象,负责管理某些其他对象并以合适的方式去控制它们。
 不管这些对象是什么,只要创建了多份,就是严重的逻辑错误。如果创建了多份基础对象,那么对应用程序中对象的访问就依赖于所 选择的那个基础对象。对于不知道存在多个基础对象的程序员来说,他们可能不知道自己考道的只是应用程序对象的一个子集。如果 存在对歌厂对象,那么对它所创建对象的控制工作就会遭到破坏。如果存在多份管理器对象,那么本来打算串行的行为就可能会变成 并发 的。
   强制对象单一性的机制似乎有些多余。毕竟,在初始化应用程序时,完全可以只创建每个对象的一个实例,然后使用该实例  。事实上,这通常也是最后的方法。在没有急迫并且有意义的需要时,应该避免使用这些机制。不过,我们也希望代码能够  传达我们的意图。如果强制对象单一性的机制是轻量级的,那么传达意图带来的收益就会胜过实施这些机制的代价。
   singleton模式额好处:
    跨平台:使用合适的中间件,可以把singleton模式扩展为跨多个JVM和多个计算机工作。
    适用于任何类:只需把一个类的构造函数变成私有额,并且在其中增加相应的静态函数和变量,就可以把这个类变成     singleton。
  可以透过派生创建:给定一个类,可以创建它的一个singleton之类。
  延迟求值:如果singleton从未使用过,那么就决不会创建它。
 singleton模式的代价 :
  摧毁方法未定义:没有好的方法去摧厚一个singleton,或者解除其职责。即使添加一个decommission方法把theInstance置为null,系统中的其他模块仍然持有对该singleton实例的应用。这样,随后对Instance方法的调用会创建另外一个实例,致使同时存在两个实例。这个问题在C++中尤为严重,应为实例可以被摧毁,可能会导致去提领一个已被摧毁的对象。
  不能继承:从singleton类派生出来的类并不是singleton。如果要使其成为singleton,必须要增加所需的静态函数和变量。
  效率问题:每次调用Instance方法都会执行if语句。就大多数调用而言,if语句是多余的。
  不透明性:singleton的使用者知道它们正在使用一个singleton,因为它们必须要调用Instance方法。
 运用singleton模式:
  假设有个基于Web的系统,它允许用户登录进入一个Web服务器的受保护的区域。这样的系统会有一个包含用户名、口令以及其他用户属性的数据库。进一步假设这个数据库是通过第三方API进行访问的。我们可以在每一个需要读写用户信息的模块中直接访问数据库。然而,这样会使得对的三方API的使用分散自爱整个代码中,并且也无法去强制实施一些访问或者结构方面的约定。
  一个比较好的解决方案是运用FACADE模式创建一个UserDatabase类,该类中包含有读写User对象的方法。这些方法调用访问数据库的的三方API,并执行User对象和数据库的表、行之间的转换工作。杂UserDatabase类中,我们可以强制实施访问和结构方面的约定。例如,我们可以保证一条User记录除非拥有非空的username,否则不予写入数据库。或者还可以把对同一个User记录的访问串行化,确保两个模块不会同时去读写它。
  
  class Singleton
  {
   public static Singleton Instance(){
    if(_instance==null){
      synchronized(Class.forname("singleton")){
       if(_instance==null){
        _instance=new singleton();
       }
      }
    }
    return _instance;
   }
   protected Singleton(){}
   private staticSingleton _instance=null;
  
  }
  
   
  class Singleton
  {
   private static Singleton _Instance=null;
   private Singleton(){}
   public static Singleton Instance()
   {
    if(_instance==null){
      _instance=new Singleton();
    return _instance;
   }
  
  }
  单件类的创建顺序:

所有内容都是充书中摘录的。

未完

原创粉丝点击