JavaScript和TypeScript的单例写法(面向对象)

原创 2017年06月11日 21:56:29

一、单例类的作用

在我们平时开发H5游戏过程中,有某别对象,希望在内存中只有一份实例,其他任何地方想要获取到这个实例,只能通过这个类提供的静态方法来获取到实例,而任何地方进行new来进行构造的话,都会报错。总结一下这个单例类的要求

  1. 这个类只允许进行一个new的调用构造函数行为
  2. 提供静态方法来访问唯一实例
  3. 提供重复new会报错的设计
  4. 具备合理优化的设计模式

二、单例设计模式

后面是借鉴的AS3的经典写法,写出的JavaScript和TypeScript版本的单例类。
这里的Singleton其实是基类的来的,子类只要继承它就自然能够获得唯一实例的判断了。相当的方便。
实际生产环境的单例基类的内部类封装:

/** 存放初始化过的构造函数 **/
private static classMap: Dictionary<any, Object> = new Dictionary();
constructor()
{
    var clazz: any = clazz = ClassUtils.forInstance(this);
    //为空时,表示浏览器不支持这样读取构造函数
    if (!clazz)
        return;
    // 防止重复实例化
    if (Singleton.classMap.hasKey(clazz))
        throw new Error(this + " 只允许实例化一次!");
    else
        Singleton.classMap.put(clazz, this);
}

可以看到把key和value用一个Dictionary对象来封装了。不过在这里就不搞太复杂了。直接给出最完整的代码。

设计原理是通过一个所有实例都共享的一个数组来存放已经初始化过的对象,然后在那个对象的构造函数里检测这个对象是否已经实例话过了。所以在这里我们就采用2个数组来存放。

/** 存放初始化过的构造函数,这里用数组来存放构造函数 **/
private static classKeys:Function[] = [];
private static classValues:any[] = [];

这里设计得比较面向对象,比较适合开发Html5游戏了。

一、TypeScript的单例写法

Singleton.ts

/**
 * 所有单例的基类,做了单例的基础检查。所有子类最好都写一个getInstance的静态方法来获取
 * @author sodaChen
 * Date:2012-10-29
 */
class Singleton
{
    //其实实际的开发项目中,不一定会用到数组,有可能会把数组之类的进行封装
    /** 存放初始化过的构造函数,这里用数组来存放构造函数 **/
    private static classKeys:Function[] = [];
    private static classValues:any[] = [];

    constructor()
    {
        var clazz: any = this["constructor"];
        //为空时,表示浏览器不支持这样读取构造函数
        if (!clazz)
            return;
        // 防止重复实例化
        if (Singleton.classKeys.indexOf(clazz) != -1)
            throw new Error(this + " 只允许实例化一次!");
        else
        {
            Singleton.classKeys.push(clazz);
            Singleton.classValues.push(this);
        }

    }
    //注意,Singleton是要替换成你自己实现的子类 这里没有实际的作用
    private static instance:Singleton;
    /**
     * 获取实例的静态方法实例
     * @return
     *
     */
    public static getInstance():Singleton
    {
        if(!this.instance)
        {
            this.instance = new Singleton();
        }
        return this.instance;
    }
    /**
     * 销毁方法。事实上单例是很少进行销毁的
     */
    destroy(o: any = null): void
    {
        this.onDestroy();
        Singleton.removeInstance(this["constructor"]);
    }

    /**
     * 子类重写的方法
     */
    protected onDestroy(): void
    {

    }
    /**
     * 删除单例的实例(不对单例本身做任何的销毁,只是删除他的引用)
     * @param clazz 单例的Class对象
     *
     */
    static removeInstance(clazz: Function): void
    {
        var index: number = this.classKeys.indexOf(clazz);
        if (index == -1)
        {
            return null;
        }
        this.classKeys.splice(index, 1);
        this.classValues.splice(index, 1);
    }

    /**
     * 是否存放有这个构造函数
     * @param clazz 构造函数
     * @return {boolean}
     */
    static getFunValue(clazz: Function):any
    {
        let funs:Function[] = this.classKeys;
        let length:number = funs.length;
        for(let i:number = 0; i < length; i++)
        {
            if(clazz == funs[i])
                return this.classValues[i];
        }
        return null;
    }

    /**
     * 获取单例类,若不存在则创建.所有的单例创建的时候,都必须使用这个方法来创建,这样可以做到统一管理单例
     * @param clazz 任意需要实现单例效果的类
     * @return
     *
     */
    static getInstanceOrCreate(clazz:any): any
    {
        var obj: any = this.getFunValue(clazz);
        if (obj)
        {
            return obj;
        }
        obj = new clazz();
        //不是Singleton的子类,则手动添加Singleton构造器会自动添加到classMap
        if (!(obj instanceof Singleton))
        {
            this.classKeys.push(clazz);
            this.classValues.push(obj);
        }
        return obj;
    }
}

测试代码:

var singleton1 = Singleton.getInstance();
console.log("通过Singleton.getInstance实例:" + singleton1);
var singleton2 = Singleton.getInstance();
console.log("singleton1 == singleton2:" + (singleton1 == singleton2));
new Singleton();

测试输出结果:

通过Singleton.getInstance实例:[object Object]
singleton1 == singleton2:true
Uncaught Error: [object Object] 只允许实例化一次!
  Singleton 
  main  
  onload

实际使用中,可以直接继承Singleton,再增加一个静态方法就可以了,比如TickMgr.ts

private static instance:TickMgr;
/**
 * 获取实例的静态方法实例
 * @return
 *
 */
public static getInstance():TickMgr
{
    if(!this.instance)
    {
        this.instance = new TickMgr();
    }
    return this.instance;
}

二、JavaScript的单例写法

原理是一样的,因为TypeScript本身就是编译成js代码的。

/**
 * 所有单例的基类,做了单例的基础检查。所有子类最好都写一个getInstance的静态方法来获取
 * @author sodaChen
 * Date:2012-10-29
 */
var Singleton = (function () {
    function Singleton() {
        var clazz = this["constructor"];
        //为空时,表示浏览器不支持这样读取构造函数
        if (!clazz)
            return;
        // 防止重复实例化
        if (Singleton.classKeys.indexOf(clazz) != -1)
            throw new Error(this + " 只允许实例化一次!");
        else {
            Singleton.classKeys.push(clazz);
            Singleton.classValues.push(this);
        }
    }
    /**
     * 获取实例的静态方法实例
     * @return
     *
     */
    Singleton.getInstance = function () {
        if (!this.instance) {
            this.instance = new Singleton();
        }
        return this.instance;
    };
    /**
     * 销毁方法。事实上单例是很少进行销毁的
     */
    Singleton.prototype.destroy = function (o) {
        if (o === void 0) { o = null; }
        this.onDestroy();
        Singleton.removeInstance(this["constructor"]);
    };
    /**
     * 子类重写的方法
     */
    Singleton.prototype.onDestroy = function () {
    };
    /**
     * 删除单例的实例(不对单例本身做任何的销毁,只是删除他的引用)
     * @param clazz 单例的Class对象
     *
     */
    Singleton.removeInstance = function (clazz) {
        var index = this.classKeys.indexOf(clazz);
        if (index == -1) {
            return null;
        }
        this.classKeys.splice(index, 1);
        this.classValues.splice(index, 1);
    };
    /**
     * 是否存放有这个构造函数
     * @param clazz 构造函数
     * @return {boolean}
     */
    Singleton.getFunValue = function (clazz) {
        var funs = this.classKeys;
        var length = funs.length;
        for (var i = 0; i < length; i++) {
            if (clazz == funs[i])
                return this.classValues[i];
        }
        return null;
    };
    /**
     * 获取单例类,若不存在则创建.所有的单例创建的时候,都必须使用这个方法来创建,这样可以做到统一管理单例
     * @param clazz 任意需要实现单例效果的类
     * @return
     *
     */
    Singleton.getInstanceOrCreate = function (clazz) {
        var obj = this.getFunValue(clazz);
        if (obj) {
            return obj;
        }
        obj = new clazz();
        //不是Singleton的子类,则手动添加Singleton构造器会自动添加到classMap
        if (!(obj instanceof Singleton)) {
            this.classKeys.push(clazz);
            this.classValues.push(obj);
        }
        return obj;
    };
    return Singleton;
}());
//其实实际的开发项目中,不一定会用到数组,有可能会把数组之类的进行封装
/** 存放初始化过的构造函数,这里用数组来存放构造函数 **/
Singleton.classKeys = [];
Singleton.classValues = [];

测试代码是一样的。

三、JavaScript更简单和比较传统的单例写法

这个写法其实就是比较偏向做js前端,而不是h5游戏的。
一般是创建一个命名空间来存放,其他地方使用就不会有new的写法了
比如

var asf = {};  

asf.singleton = {} ;  
asf.TickMgr = {};  

外面则是直接调用

asf.singleton.pay("mc");
asf.TickMgr.tick();
版权声明:本文为博主原创文章,转载必须声明出处和作者。地址:http://blog.csdn.net/sujun10 作者:弃天笑

TypeScript 面向对象基础知识

孙广东  2016.4.5JavaScript如今到处都是,web、服务器(通过NodeJS)、移动应用(通过各种框架),所有这些,TypeScript都可以使用,并且可以为JavaScript扩展出...

Singleton单例模式——类模板单例

概述:         singleton模式称作单件模式或单例模式。它的作用是确保一个类在整个工程中有且只有一个实例。可以在多个不同的类中很方便的所需要的类的方法。 应用领域:常用在游戏编程和多...

TypeScript 强制类型转换和类型判断 typeof,instanceof

作为一名AS3老手,写TS也是手到擒来的事情,不过AS和TS还是有些习惯不太一样,比如类型判断这块 AS3中只需要一个 ‘as’ ‘is’关键字就可以了 TS则不然,它的类型判断比较特殊,下面的方...

Egret TypeScript基本写法学习文档

基本类型 基础类型只有这么几种,与AS3对比 TypeScript     ActionScript3 number     Number string     String boole...

Egret开发《消灭方块》后记(二)对象池的应用

对于性能的追求是永无止境的,此文只做抛砖引玉,欢迎讨论。 用好对象池绝对能提高很多项目的执行效率,下面结合我在《消灭方块》的开发介绍一下对象池的应用。...

Java中的嵌套类、内部类、静态内部类

嵌套类可以分为两种,静态的和非静态的,即静态嵌套类和非静态嵌套类。非静态嵌套类又叫做内部类(Inner Class)。我们通常所说的静态内部类其实是不严格的,严格的说应该叫做静态嵌套类(Static ...

gulp中task 正确的异步执行:加上return

邂逅问题 一个老工程,比较乱,里面有前同事写的一个简单的gulp的task,里面有这些东西: gulp.task('dev', ['css', 'js'], function () { ...

以同步的方式运行 Gulp 任务和任务中的步骤

原文:https://blog.jijiechen.com/post/run-gulp-tasks-and-steps-synchronously?utm_source=tuicool&utm_med...

javascript面向对象写法--极简主义法

初学js时感觉js的语法真心恶。后来逐渐熟悉了而且适应了也没当初的反感。最近网上看到了一种面向对象的写法,给大家分享一下。(我的第一文章) 这种写法被称为"极简主义法",是荷兰程序员 Gabor d...

黑马程序员------毕老师视频笔记第六天------面向对象(单例设计模式)

java中有23中通用的设计模式 设计模式:解决某一类问题最行之有效的方法   单例设计模式:解决一个类在内存中只存在一个对象的问题   想要保证对象唯一: ①为了避免其他程序过多的建立该...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:JavaScript和TypeScript的单例写法(面向对象)
举报原因:
原因补充:

(最多只允许输入30个字)