JS中的单例模式和抽象 [英] Singleton Pattern and Abstraction in JS

查看:171
本文介绍了JS中的单例模式和抽象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

虽然下面的例子利用了ExtJS,可以很容易地推断出另一个框架。我是抽象和数据隐藏的粉丝(一般是OO);有没有人隐藏数据和成员/功能,还是认为这个尝试是过度的?



(注意:我强烈地认为,DOM ID几乎不会被硬编码,尽管我使用原型为典型类的公共方法,你会注意到下面的一个公共函数在原型之外创建。)



这个说明很有趣 http://yuiblog.com/blog/2007/06/12/module-pattern/

  Ext.ns( 'Foo.Bar'); 

/ **
* Foo.Bar.MainToolbar(singleton)
* /
Foo.Bar.MainToolbar =(function()
{
//用于创建和返回对象的临时私有类 - 单例
var toolbarClass = Ext.extend(Ext.Container,
{
/ **
*构造函数(public)
* /
构造函数:function(config)
{
config = config || {};

//私有成员数据====================================

/ /需要动画锚的ID
var accountId = Ext.id(null,'ls-accountDiv-');
var faqId = Ext.id(null,'ls-faqDiv-');
var logoutId = Ext.id(null,'ls-logoutDiv-');
var loginId = Ext.id(null,'ls-loginDiv-');
var rulesId = Ext.id (null,'ls-rulesDiv-');

var itemCls =
'color:white; cursor:pointer; font-weight:bold;'+
'家庭:Helvetica,Arial,Verdana,Lucida Sa ns Unicode,Sans-serif;';


//公共方法************************* ********************

/ **
* userLogin(public) -
* /
this.userLogin = function(userName,password)
{
//更新标题栏
Ext.fly(accountId).update(userName);
Ext.fly(loginId).hide(true);
Ext.fly(logoutId).show(true);
};

//私人方式************************************ ******

/ **
* handleFaqClick(私人) - 点击常见问题的处理程序
* /
var handleFaqClick = function(event)
{
var dialogMsg ='< div style =text-align:leftblah,blah< / div>';

Ext.Msg.show({
标题:'FAQ',
modal:true,
msg:dialogMsg,
animEl:faqId,
按钮:Ext.Msg.OK,
图标:Ext。 MessageBox.QUESTION,
minWidth:'700'
});
};

/ **
* handleLogoutClick(私人) - 点击处理程序注销
* /
var handleLogoutClick = function(event)
{
Ext.fly(accountId).update('');
Ext.fly(logoutId ).hide(true);
Ext.fly(loginId).show(true);
};

/ **
*手leRulesClick(private) - 点击RULES的处理程序
* /
var handleRulesClick = function(event)
{
var dialogMsg =
'< div style = text-align:left;>< br />< b> blah,blah< / div>';

Ext.Msg.show({
title:'Rules',
modal:true,
msg:dialogMsg,
animEl:rulesId,
按钮:Ext.Msg.OK,
图标:Ext.MessageBox.INFO,
minWidth:'700'
});
};


//建筑师=============================== ============

//忽略用户提供的某些参数(可能)
config.id = Ext.id(null,'ls- mainToolbar-');
config.layout ='absolute';
config.layoutConfig = {};
config.height = 38;
config.width = 968;

config.items = [
{
id:Ext.id(null,'ls-mainToolbar-'),
xtype:'box',x: 25,y:0,height:36,
autoEl:{tag:'img',src:'./images/top_toolbar.png'}

},{
id:Ext.id(null,'ls-logo-'),
xtype:'box',
x:70,y:8,height:22,width:200,
autoEl :{style:itemCls,html:'Foo Bar'}
},{
id:accountId,
xtype:'box',
x:470,y:8,height :22,width:200,
autoEl:{style:itemCls +'text-align:right;',html:''}
},{
id:logoutId,
xtype:'box',x:730,y:8,height:22,width:36,
autoEl:{style:itemCls +'visibility:hidden;',html:'logout'},
listeners:
{render:
function(cmp){
cmp.getEl()。addListener('click',
handleLogoutClick.createDelegate(this))
} .createDelegate(this)
}
},{
id:loginId,
xtype:'box',x:730 ,y:8,height:22,width:36,
autoEl:{style:itemCls,html:'login'},
listeners:
{render:
function cmp){
cmp.getEl()。addListener('click',
Foo.Bar.LoginDialog.show.createDelegate(
Foo.Bar.LoginDialog,[Ext.emptyFn]))
}
}
},{
id:rulesId,
xtype:'box',x:800,y:8,height:22,width:36 ,
autoEl:{style:itemCls,html:'rules'},
listeners:
{render:
函数(cmp){
cmp.getEl .addListener('click',
handleRulesClick.createDelegate(this))
} .createDelegate(this)
}
},{
id:faqId,
xtype:'box',x:860,y:8,height:22,width:26,
autoEl:{style :itemCls,html:'faq'},
listeners:
{render:
函数(cmp){
cmp.getEl()。addListener('click',
handleFaqClick.createDelegate(this))
} .createDelegate(this)
}
}];

toolbarClass.superclass.constructor.apply(this,[config]);

Foo.Bar.LoginDialog.addListener(
Foo.Bar.LoginDialog.LOGIN_SUCCESSFUL_EVENT(),
this.userLogin.createDelegate(this));
}
});

返回new toolbarClass();
})();


解决方案

小心隐藏JavaScript中的数据通常是但这可能也是一个很好的主意,尤其是当你创建一个图书馆,并希望消费者使用图书馆的公共API,而不是乱七八糟的内部人物(很多富有想象力的人)。



在JavaScript中,隐藏数据/方法的模式通常会创建一个关闭,您拥有所有私有内容,并让您的公共API方法可以访问该关闭。



简单的例子:

  var API =(function(){
//内部的东西进入这里
// ...
//某些公共方法我会稍后公开
//所有都可以访问内部,因为它们在封闭内
函数method1(){...}
function method2(){...}
var somevar;
return {
public_method1:method1,
public_method2 :method2,
public_var:somevar,
};
})();

//使用API​​:
API.public_method1();


Although the example below exploits ExtJS, one can easily extrapolate to another framework. I am a fan of abstraction and data hiding (and OO in general); does anyone else hide data and members/functions or do you consider this attempt to be overkill?

(Note: I believe strongly that DOM IDs should almost never be hardcoded. And, though I use prototypes for public methods of typical classes, you will notice a public function below created outside of the prototype.)

This note is interesting http://yuiblog.com/blog/2007/06/12/module-pattern/

Ext.ns('Foo.Bar');

/**
 * Foo.Bar.MainToolbar (singleton)
 */
Foo.Bar.MainToolbar = (function()
{
  // Temporary, private class used to create and return an object - a singleton
  var toolbarClass = Ext.extend( Ext.Container,
  {
    /**
     * constructor (public)
     */
    constructor: function( config )
    {
      config = config || {};

      // PRIVATE MEMBER DATA ========================================

      // Need IDs for animation anchors
      var accountId = Ext.id( null, 'ls-accountDiv-');
      var faqId = Ext.id( null, 'ls-faqDiv-');
      var logoutId = Ext.id( null, 'ls-logoutDiv-');
      var loginId = Ext.id( null, 'ls-loginDiv-');
      var rulesId = Ext.id( null, 'ls-rulesDiv-');

      var itemCls =
        'color: white; cursor: pointer; font-weight: bold; ' +
        'font-family:Helvetica,Arial,Verdana,Lucida Sans Unicode,Sans-serif;';


      // PUBLIC METHODS *********************************************

      /**
       * userLogin (public) -
       */
      this.userLogin = function( userName, password )
      {
        // Update title bar
        Ext.fly(accountId).update( userName );
        Ext.fly(loginId).hide(true);
        Ext.fly(logoutId).show(true);
      };

      // PRIVATE METHODS ********************************************

      /**
       * handleFaqClick (private) - handler for click on FAQ
       */
      var handleFaqClick = function( event )
      {
        var dialogMsg = '<div style="text-align: leftblah, blah</div>';

        Ext.Msg.show({
          title: 'FAQ',
          modal: true,
          msg: dialogMsg,
          animEl: faqId,
          buttons: Ext.Msg.OK,
          icon: Ext.MessageBox.QUESTION,
          minWidth: '700'
        });
      };

      /**
       * handleLogoutClick (private) - handler for click on logout
       */
      var handleLogoutClick = function( event )
      {
        Ext.fly(accountId).update('');
        Ext.fly(logoutId).hide(true);
        Ext.fly(loginId).show(true);
      };

      /**
       * handleRulesClick (private) - handler for click on RULES
       */
      var handleRulesClick = function( event )
      {
        var dialogMsg = 
          '<div style="text-align: left;"><br/><b>blah, blah</div>';

        Ext.Msg.show({
          title: 'Rules',
          modal: true,
          msg: dialogMsg,
          animEl: rulesId,
          buttons: Ext.Msg.OK,
          icon: Ext.MessageBox.INFO,
          minWidth: '700'
        });
      };


      // CONSTRUCTOR  ===============================================

      // Some parameters (possibly) offered by the user are ignored
      config.id = Ext.id( null, 'ls-mainToolbar-');
      config.layout = 'absolute';
      config.layoutConfig = {};
      config.height = 38;
      config.width = 968;

      config.items = [
      {
        id: Ext.id( null, 'ls-mainToolbar-'),
        xtype: 'box', x: 25, y: 0, height: 36, 
        autoEl: { tag: 'img', src: './images/top_toolbar.png' }

      },{
        id: Ext.id( null, 'ls-logo-'),
        xtype: 'box',
        x: 70, y: 8, height: 22, width: 200,
        autoEl: { style: itemCls, html: 'Foo Bar' }
      },{
        id: accountId,
        xtype: 'box',
        x: 470, y: 8, height: 22, width: 200,
        autoEl: { style: itemCls + ' text-align: right;', html: ' ' }
      },{
        id: logoutId,
        xtype: 'box', x: 730, y: 8, height: 22, width: 36,
        autoEl: {style: itemCls + ' visibility: hidden;', html: 'logout'},
        listeners:
          { render:
            function( cmp ){
              cmp.getEl().addListener('click', 
                handleLogoutClick.createDelegate(this))
            }.createDelegate(this)
          }
      },{
        id: loginId,
        xtype: 'box', x: 730, y: 8, height: 22, width: 36,
        autoEl: { style: itemCls, html: 'login' },
        listeners:
          { render:
            function( cmp ){
              cmp.getEl().addListener('click',
                Foo.Bar.LoginDialog.show.createDelegate(
                  Foo.Bar.LoginDialog, [Ext.emptyFn]))
            }
          }
      },{
        id: rulesId,
        xtype: 'box', x: 800, y: 8, height: 22, width: 36,
        autoEl: { style: itemCls, html: 'rules'},
        listeners:
          { render:
            function( cmp ){
              cmp.getEl().addListener( 'click', 
                handleRulesClick.createDelegate(this) )
            }.createDelegate(this)
          }
      },{
        id: faqId,
        xtype: 'box', x: 860, y: 8, height: 22, width: 26,
        autoEl: { style: itemCls, html: 'faq'},
        listeners:
          { render:
            function( cmp ){
              cmp.getEl().addListener( 'click', 
                handleFaqClick.createDelegate(this) )
            }.createDelegate(this)
          }
      }];

      toolbarClass.superclass.constructor.apply( this, [config] );

      Foo.Bar.LoginDialog.addListener(
        Foo.Bar.LoginDialog.LOGIN_SUCCESSFUL_EVENT(), 
          this.userLogin.createDelegate(this));
    }
  });

  return new toolbarClass();
})();

解决方案

Taking the care to hide data in JavaScript is usually an overkill, but it might be also a very good idea especially when you're creating a library and want consumers to use the library's public API and not mess around with the internals (lots of imaginative people like that).

In JavaScript the pattern for hiding data/methods is usually creating a closure where you have all your private stuff and let your public API methods with access to that closure.

Simplistic example:

var API = (function() {
    // internal stuff goes in here
    // ...
    // some public methods i'll expose later
    // all have access to the internals since they're inside the closure
    function method1() { ... }
    function method2() { ... }
    var somevar;
    return {
        public_method1: method1,
        public_method2: method2,
        public_var: somevar,
    };
})();

// use the API:
API.public_method1();

这篇关于JS中的单例模式和抽象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆