JS中的单例模式和抽象 [英] Singleton Pattern and Abstraction in JS
问题描述
(注意:我强烈地认为,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屋!