Javascript实现单例模式,设计模式之单例模式
分类:多线程

Javascript实现单例模式,javascript实现

单例模式也称作为单子模式,更多的也叫做单体模式。为软件设计中较为简单但是最为常用的一种设计模式。

单例模式的介绍:

    在应用单例模式时,生成单例的类必须保证只有一个实例的存在,很多时候整个系统只需要拥有一个全局对象,才有利于协调系统整体的行为。比如在整个系统的配置文件中,配置数据有一个单例对象进行统一读取和修改,其他对象需要配置数据的时候也统一通过该单例对象来获取配置数据,这样就可以简化复杂环境下的配置管理。

    单例模式的思路是:一个类能返回一个对象的引用(并且永远是同一个)和一个获得该实例的方法(静态方法,通常使用 getInstance 名称)。那么当我们调用这个方法时,如果类持有的引用不为空就返回该引用,否者就创建该类的实例,并且将实例引用赋值给该类保持的那个引用再返回。同时将该类的构造函数定义为私有方法,避免其他函数使用该构造函数来实例化对象,只通过该类的静态方法来得到该类的唯一实例。

一般情况下,Javascript每次new一个对象就产生一个实例,实例指向不同的地址。就像如下:

(function(){
function Person(name){
this.name = name;
}
Person.prototype.work = function(){
console.log(this.name + " is working");
}
var p1 = new Person("Darren");
p1.work();
var p2 = new Person("Jack");
p2.work();
}());

以上,每次new出一个Person对象都是不同的。

如何在Javascript中实现单例模式呢?

--在生成某各对象时先判断是否存在。存在就不生成对象,不存在就生成对象。

(function(){
var PersonSingleton = (function(){
var instance;
function init(){
return {
name: 'Anonymous',
work: function(){
console.log(this.name + ' working');
}
};
}
return {
getInstance: function(){
if(!instantiated){
instantiated = init();
}
return instantiated;
}
}
})();
var p1 = PersonSingleton.getInstance();
p1.work();
var p2 = PersonSingleton.getInstance();
p2.work();
}());

以上,通过PsonSIngleton对象的getInstance方法得到的实例每次都是一样的。

关于javascript单例模式的相关知识就给大介绍到这里,希望对大家有所帮助。

这篇文章主要介绍了什么是单例单例模式、使用场景,提供了3个示例给大家参考

前言

本篇博客归类于设计模式,单例模式算是我了解的不多的设计模式之一,在某些应用场景下为了节省资源,常常使用单例模式来编写代码。

单例模式(Singleton Pattert)是一种常用的软件设计模式,该模式的主要目的是确保在某一个类中能且只能产生一个实例。当在某些场景下希望某个类只能产生一个实例时,就可以使用单例模式了。

您可能感兴趣的文章:

  • javascript 单例模式演示代码 javascript面向对象编程
  • JavaScript的单例模式 (singleton in Javascript)
  • js单例模式的两种方案
  • js单例模式详解实例
  • JavaScript设计模式之单例模式实例
  • 深入理解JavaScript系列(25):设计模式之单例模式详解
  • JS模式之单例模式基本用法
  • javascript单例模式的简单实现方法

单例模式也称作为单子模式,更多的也叫做单体模式。为软件设计中较为简单但是最为常用的一种设计...

什么是单例?

python 中的单例模式

单例模式也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。

实现单例模式的思路是:一个类能返回对象一个引用和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名称);当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。

单例模式在多线程的应用场合下必须小心使用。如果当唯一实例尚未创建时,有两个线程同时调用创建实例方法,那么它们同时没有检测到唯一实例的存在,从而同时各自创建了一个实例,这样就有两个实例被构造出来,从而违反了单例模式中实例惟一的原则。解决这个问题的办法是为指示是否已经实例化的变量提供一个互斥锁(虽然这样会降低效率)。

在面向对象编程中,学习了使用某一个类来创建多个不同的对象,那么如何使得该类只能产生一个对象呢?

在Python 中,可以使用多种方法来实现单例模式:

  1. 使用模块
  2. 使用魔术方法__new__
  3. 使用装饰器
  4. 使用元类

单例要求一个类有且只有一个实例,提供一个全局的访问点。因此它要绕过常规的控制器,使其只能有一个实例,供使用者使用,而使用着不关心有几个实例,因此这是设计者的责任

使用模块

python 中的模块就是天然的单例模式,因为模块只会在第一次导入的时候加载,会生成一个 .pyc文件,第二次导入时,就会直接加载 .pyc文件,而不会再次执行模块代码。因此,可以把相关的代码和数据定义在一个模块中,就可以获得一个单例对象了。然后要用的话导入就可以,我可以保证这样做的话肯定只有一个单例对象。代码就不演示了。

In JavaScript, Singletons serve as a shared resource namespace which isolate implementation code from the global namespace so as to provide a single point of access for functions.

使用特殊方法__new__

在使用类实例化一个对象时,其实python 解释器做了两步操作:

  1. 调用 object 的__new__方法创建一个空对象;
  2. 调用类本身的__init__方法进行初始化(这都是通过元类的__call__来间接调用的)

那么是不是可以在调用__new__的时候做一些判断来使得只能创建一个单例对象呢?

class Singleinstance:    _instance = None    def __new__(cls, *arg, **kwargs):        if not cls._instance:            cls._instance = super(Singleinstance, cls).__new__(cls, *args, **kwargs)        return cls._instanceclass MyClass(Singleinstance):    a = 1

在上面的代码中,将类的__new__方法和一个类的属性关联起来,如果 cls._instance 为 None 则创建一个对象,否则的话直接返回cls._instance。

在javascript中,单例被当做一个全局的命名空间,提供一个访问该对象的一个点。

使用装饰器

装饰器可以动态的修改一个类或者函数的功能。所以可以使用装饰器来装饰某各类,使其只能生成一个实例:

from functools import wrapsdef singleinstance:    instances = {}    @wraps    def getinstance(*args, **kwargs):        if cls not in instances:            instances[cls] = cls(*args, **kwargs)        return instances[cls]    return getinstance@singleinstanceclass MyClass:    a = 1

在上面,定义了一个装饰器 singleinstance,它返回了一个内部函数getinstance,该函数会判断某个类是否在字典 instance 中,如果不存在,则会将 cls 作为 key,cls(*args, **kwargs)作为 value存到 instances 中,否则,直接返回 instances[cls]。该装饰器可以装饰所有只需要产生一个实例的类上。

使用场景

使用 metaclass

元类 metaclass 可以通过自定义__new__方法和__init__方法来控制类的创建过程,它主要做三件事:

  • 拦截类的创建
  • 修改类的定义
  • 返回修改后的类

使用元类实现单例的代码如下:

class MyMetaClass:    # def __init__:    #     pass    instance = None    def __call__(cls, *args, **kwargs):        # 判断对象有没有创建过        if not MyMetaClass.instance:            # 创建空对象            MyMetaClass.instance = object.__new__            print(cls.__name__)            print(cls.__dict__)            print("创建新的播放器对象!")            # 初始化对象            MyMetaClass.instance.__init__(*args,**kwargs)            print(type(MyMetaClass.instance))            # 返回对象        return MyMetaClass.instanceclass CDPlayer(metaclass=MyMetaClass):    pass     
In practice, the Singleton pattern is useful when exactly one object is needed to coordinate others across a system. 

单例比较适用于一个对象和其他系统进行交互。

类比

单例有点类似于一个小组的小组长,在一段时间内只有一个小组长,有小组长来指定组员的工作,分配和协调和组员的工作。

实例1:这个是最简单的单例,通过key,value的形式存储属性和方法

var A = {
   xx:3,
   yy:4,
   B:function(el){

   },
   C:function(el){

   },
   D:function(el){

   },
   E:function(el){

   }
}

实例2:首先创建一个实例的引用,然后判断这个实例是否存在,如果不存在那么就创建,存在的话,就直接返回,保证有且只有一个。

var mySingleton = (function () {


// Instance 存储一个单例实例的引用
var instance;

function init() {

// Singleton

// 私有的方法和变量
function privateMethod(){
    console.log( "I am private" );
}

var privateVariable = "Im also private";

return {

  // 共有的方法和变量
  publicMethod: function () {
    console.log( "The public can see me!" );
  },

  publicProperty: "I am also public"
};

};

return {

// 如果实例不存在,那么创建一个
getInstance: function () {

  if ( !instance ) {
    instance = init();
  }

  return instance;
}

};

})();

var singleA = mySingleton;
var singleB = mySingleton;
console.log( singleA === singleB ); // true

实例3:

var SingletonTester = (function () {
  // options: an object containing configuration options for the singleton
  // e.g var options = { name: "test", pointX: 5}; 
  function Singleton( options )  {
    // set options to the options supplied
    // or an empty object if none are provided
    options = options || {};
    // set some properties for our singleton
    this.name = "SingletonTester";
    this.pointX = options.pointX || 6;
    this.pointY = options.pointY || ; 
  }
  // our instance holder 
  var instance;
  // an emulation of static variables and methods
  var _static  = {  
    name:  "SingletonTester",
    // Method for getting an instance. It returns
    // a singleton instance of a singleton object
    getInstance:  function( options ) {   
      if( instance  ===  undefined )  {    
        instance = new Singleton( options );   
      }   
        return  instance;      
    } 
  }; 
  return  _static;
})();
var singletonTest  =  SingletonTester.getInstance({
  pointX:  5
});
// Log the output of pointX just to verify it is correct
// Outputs: 5
console.log( singletonTest.pointX ); 

 

 

单例模式

 

    单例模式也称作为单子模式,更多的也叫做单体模式。为软件设计中较为简单但是最为常用的一种设计模式。

 

    下面是维基百科对单例模式的介绍:

    在应用单例模式时,生成单例的类必须保证只有一个实例的存在,很多时候整个系统只需要拥有一个全局对象,才有利于协调系统整体的行为。比如在整个系统的配置文件中,配置数据有一个单例对象进行统一读取和修改,其他对象需要配置数据的时候也统一通过该单例对象来获取配置数据,这样就可以简化复杂环境下的配置管理。

    单例模式的思路是:一个类能返回一个对象的引用(并且永远是同一个)和一个获得该实例的方法(静态方法,通常使用 getInstance 名称)。那么当我们调用这个方法时,如果类持有的引用不为空就返回该引用,否者就创建该类的实例,并且将实例引用赋值给该类保持的那个引用再返回。同时将该类的构造函数定义为私有方法,避免其他函数使用该构造函数来实例化对象,只通过该类的静态方法来得到该类的唯一实例。

 

    对于 JS 来说,巨大的灵活性使得其可以有多种方式实现单例模式,使用闭包方式来模拟私有数据,按照其思路可得:

  1. var single = (function(){
  2.     var unique;
    1.     function getInstance(){
  3.         if( unique === undefined ){
  4.             unique = new Construct();
  5.         }
  6.         return unique;
  7.     }
    1.     function Construct(){
  8.         // ... 生成单例的构造函数的代码
  9.     }
    1.     return {
  10.         getInstance : getInstance
  11.     }
  12. })();

    以上,unique便是返回对象的引用,而 getInstance便是静态方法获得实例。Construct 便是创建实例的构造函数。

    可以通过 single.getInstance() 来获取到单例,并且每次调用均获取到同一个单例。这就是 单例模式 所实现的效果。

 

    不过,对于JS来说,显然以上循规蹈矩的方式显得过于笨重,在不同的场景以不同的方式实现单体模式正是 JS 的优势

    

    实现1: 最简单的对象字面量

  1. var singleton = {
  2.         attr : 1,
  3.         method : function(){ return this.attr; }
  4.     }
    1. var t1 = singleton ;
  5. var t2 = singleton ;

    那么很显然的, t1 === t2 。

 

    十分简单,并且非常使用,不足之处在于没有什么封装性,所有的属性方法都是暴露的。对于一些需要使用私有变量的情况就显得心有余而力不足了。当然在对于 this 的问题上也是有一定弊端的。

 

 

    实现2:构造函数内部判断

    其实和最初的JS实现有点类似,不过是将对是否已经存在该类的实例的判断放入构造函数内部。

  1. function Construct(){
  2.     // 确保只有单例
  3.     if( Construct.unique !== undefined ){
  4.         return Construct.unique; 
  5.     }
  6.     // 其他代码
  7.     this.name = "NYF";
  8.     this.age="24";
  9.     Construct.unique = this;
  10. }
    1. var t1 = new Construct() ;
  11. var t2 = new Construct() ;

    那么也有的, t1 === t2 。

    也是非常简单,无非就是提出一个属性来做判断,但是该方式也没有安全性,一旦我在外部修改了Construct的unique属性,那么单例模式也就被破坏了。

    

    实现3 : 闭包方式    

    对于大着 灵活 牌子的JS来说,任何问题都能找到 n 种答案,只不过让我自己去掂量孰优孰劣而已,下面就简单的举几个使用闭包实现单例模式的方法,无非也就是将创建了的单例缓存而已。

 

  1. var single = (function(){
  2.     var unique;
  3.     function Construct(){
  4.         // ... 生成单例的构造函数的代码
  5.     }
    1.     unique = new Constuct();
    1.     return unique;
  6. })();

    只要 每次讲 var t1 = single; var t2 = single;即可。 与对象字面量方式类似。不过相对而言更安全一点,当然也不是绝对安全。

    如果希望会用调用 single() 方式来使用,那么也只需要将内部的 return 改为

    

    return function(){

        return unique;

    } 

    以上方式也可以使用 new 的方式来进行(形式主义的赶脚)。当然这边只是给了闭包的一种例子而已,也可以在 Construct 中判断单例是否存在 等等。 各种方式在各个不同情况做好选着即可。

 

总结

    总的来说,单例模式相对而言是各大模式中较为简单的,但是单例模式也是较为常用并且很有用的模式。在JS中尤为突出(每个对象字面量都可以看做是一个单例么~)。

    记住,是否严格的只需要一个实例对象的类(虽然JS没有类的概念),那么就要考虑使用单例模式。

    使用数据缓存来存储该单例,用作判断单例是否已经生成,是单例模式主要的实现思路。

本文由10bet手机官网发布于多线程,转载请注明出处:Javascript实现单例模式,设计模式之单例模式

上一篇:CentOS下./configure && make && make install 下一篇:没有了
猜你喜欢
热门排行
精彩图文