OSDN Git Service

76e0957c2bee9a7828d2dc45e85ec02f4e5808cb
[pettanr/clientJs.git] / 0.6.x / js / 00_core / 04_XClass.js
1 /**\r
2  * Class を定義し システムの管理下に置く.\r
3  * 全てのクラスと pool が有効の場合インスタンスへの参照が保持される.\r
4  *  1. X.Class.create( def, opt_final, opt_pool, opt_abstract ) でクラスを登録.\r
5  *  2. コンストラクタ となるメソッドは、Constructor : function( arg ){ ... }, に書く.\r
6  *  3. 通常通り new で インスタンス生成\r
7  *  4. kill() でオブジェクトをクリーンして削除、pool が有効の場合は pool される.\r
8  *  5. pool が有効の場合、new で pool されたインスタンスが返される.\r
9  *  6. \r
10  * \r
11  */\r
12 X.Class = ( function(){\r
13         var CLASS_LIST         = [],\r
14                 DEF_LIST           = [],\r
15                 PRIVATE_CLASS_LIST = [],\r
16                 PRIVATE_DEF_LIST   = [],\r
17                 CONSTRUCTOR        = 'Constructor',\r
18                 killPrivateFlag    = false,\r
19                 traits             = null,\r
20                 useObjectCreate    = false, // !!Object.create, http://jsperf.com/prototype-vs-object-create-perf\r
21                 use__proto__       = !!X.emptyFunction.prototype.__proto__;\r
22         _DEF_LIST = DEF_LIST;\r
23         /* サブクラスを作るメソッド  \r
24          * var subClass = superClass.inherits( ... ) \r
25          * http://d.hatena.ne.jp/m-hiyama/20051018/1129605002\r
26          */\r
27         function inherits( /* displayName, classSetting, opt_PrivateClass, props */ ){\r
28                 var args        = X.copyArray( arguments ),\r
29                         params      = [],\r
30                         Super       = this,\r
31                         superDef    = X.Class._getClassDef( Super ),\r
32                         displayName = args[ 0 ],\r
33                         classSetting,\r
34                         opt_super,\r
35                         klass, def;\r
36                 if( superDef.Final ) X.Notification.critical( 'X.Class inherits, Class is final!' );\r
37                 \r
38                 // サブクラス名\r
39                 if( X.Type.isString( displayName ) ){\r
40                         args.shift();\r
41                 } else {\r
42                         displayName = 'SubClass of ' + superDef.displayName;\r
43                 };\r
44                 params.push( displayName );\r
45                 \r
46                 // サブクラス設定\r
47                 classSetting = args[ 0 ];\r
48                 if( X.Type.isNumber( classSetting ) ){\r
49                         args.shift();\r
50                 } else {\r
51                         // クラス設定がない場合、親からコピーして、Abstract flag は落とす??\r
52                         classSetting = superDef.setting;// &= ~X.Class.ABSTRACT;\r
53                 };\r
54                 if( superDef.isPrivate ) classSetting = classSetting | X.Class.PRIVATE_DATA;\r
55                 opt_super = !!( classSetting & X.Class.SUPER_ACCESS );\r
56                 params.push( classSetting );\r
57 \r
58                 // サブクラスのシャドウ\r
59                 if( args[ 0 ] && X.Class._getClass( args[ 0 ] ) ){\r
60                         params.push( args.shift() );\r
61                 } else\r
62                 if( superDef.privateClass ){\r
63                         params.push( superDef.privateClass );\r
64                 };\r
65                 params.push( args[ 0 ] ); /* props サブクラスでは未定義でも可 */\r
66                 \r
67                 // 継承クラスの作成\r
68                 if( useObjectCreate ){\r
69                         traits = Object.create( Super.prototype );\r
70                 } else\r
71                 if( use__proto__ ){\r
72                         traits = Super.prototype;\r
73                 } else {\r
74                         Super.__new = null;\r
75                         traits = new Super();\r
76                         Super.__new = C;                        \r
77                 };\r
78                 klass  = X.Class.create.apply( X.Class, params );\r
79                 traits = null;\r
80                 \r
81                 // 継承用プロパティを控える\r
82                 if( opt_super === true ){\r
83                         def = X.Class._getClassDef( klass );\r
84                         def.Super = Super;\r
85                         def.SuperProto = Super.prototype;\r
86                         def.SuperConstructor = superDef[ CONSTRUCTOR ] || superDef.SuperConstructor;\r
87                 };\r
88                 \r
89                 return klass;\r
90         };\r
91         \r
92         /* X.Class.create で作られたクラスのインスタンスが共通で備えるメソッド \r
93          *\r
94          *\r
95          */\r
96         var CommonProps = {\r
97                 kill : function(){\r
98                         var instance = this,\r
99                                 klass    = X.Class._getClass( instance ),\r
100                                 def      = X.Class._getClassDef( klass ),\r
101                                 data, p, i;\r
102                         if( def.isPrivate && !killPrivateFlag ){\r
103                                 X.Notification.critical( 'PrivateInstance.kill() work in PrivateUser.kill().' );\r
104                                 return;\r
105                         };\r
106                         killPrivateFlag = false; // onKill 内で PrivateInstance.kill() を防ぐため\r
107                         \r
108                         // onKill() === false の場合、kill のキャンセル\r
109                         // private      は false での キャンセル は無視される\r
110                         if( this.instanceOf( X.EventDispatcher ) ){\r
111                                 if( !def.isPrivate ){\r
112                                         if( this._dispatching ){\r
113                                                 this.dispatch( X.Event.BEFORE_KILL_INSTANCE );\r
114                                                 this._killReserved = true;\r
115                                                 this.dispatch( X.Event.KILL_INSTANCE_CANCELED );\r
116                                                 return;\r
117                                         } else\r
118                                         if( this.dispatch( X.Event.BEFORE_KILL_INSTANCE ) & X.Callback.PREVENT_DEFAULT ){\r
119                                                 this.dispatch( X.Event.KILL_INSTANCE_CANCELED );\r
120                                                 return;\r
121                                         };\r
122                                 };\r
123                                 this.dispatch( X.Event.BEFORE_KILL_INSTANCE );\r
124                                 this.dispatch( X.Event.KILL_INSTANCE );\r
125                                 this._listeners && this.unlisten();\r
126                         } else\r
127                         if( X.Type.isFunction( instance.onKill ) && instance.onKill() === false && !def.isPrivate ){\r
128                                 return;\r
129                         };\r
130                         \r
131                         for( p in instance ){\r
132                                 if( instance.hasOwnProperty && !instance.hasOwnProperty( p ) ) continue;\r
133                                 delete instance[ p ];\r
134                         };\r
135                         if( def.pool ){\r
136                                 def.live && def.live.splice( def.live.indexOf( instance ), 1 );\r
137                                 def.pool[ def.pool.length ] = instance;\r
138                         };\r
139                         if( def.privateClass ){\r
140                                 i = def.userList.indexOf( instance );\r
141                                 if( i !== -1 ){\r
142                                         data            = X.Class._getPrivate( instance );\r
143                                         killPrivateFlag = true;\r
144                                         if( data._dispatching && data.instanceOf( X.EventDispatcher ) ){\r
145                                                 data._killReserved = true;\r
146                                         } else {\r
147                                                 data.kill();\r
148                                         };\r
149                                         def.dataList.splice( i, 1 );\r
150                                         def.userList.splice( i, 1 );\r
151                                 };\r
152                         };\r
153                 },\r
154                 \r
155                 // Super\r
156                 // SuperCall\r
157                 \r
158                 instanceOf : function( klass ){\r
159                         var Super = this;\r
160                         if( this.constructor === klass ) return true;\r
161                         while( Super = X.Class._getClassDef( Super ).Super ){\r
162                                 if( Super === klass ) return true;\r
163                         };\r
164                         return false;\r
165                 }\r
166         };\r
167         \r
168         /*\r
169          * new の実体.コンストラクタの機能は instance.Constructor に書く.\r
170          * これにより pool された オブジェクト(破棄されたインスタンス) を再利用できる\r
171          */\r
172         /* Constructor Real for GeneralClass */\r
173         function C( args ){\r
174                 var klass    = this,\r
175                         def      = X.Class._getClassDef( klass ),\r
176                         dataUser = def._tempUser,\r
177                         instance, obj,\r
178                         userDef;\r
179                 if( def.Abstract === true ){\r
180                         X.Notification.critical( 'AbstractClass!' );\r
181                         return;\r
182                 };\r
183                 if( def.isPrivate === true && dataUser === null ){\r
184                         X.Notification.critical( 'use myClass.newPrivate( instance, ...args )!' );\r
185                         return;\r
186                 };\r
187                 klass.__new = null;\r
188                 instance = def.pool && def.pool.length > 0 ?\r
189                                                 def.pool.pop() :\r
190                                         useObjectCreate ?\r
191                                                 Object.create( klass.prototype ) :\r
192                                                 new klass();\r
193                 klass.__new = C;\r
194                 if( def.isPrivate === true ){\r
195                         userDef = X.Class._getClassDef( dataUser );\r
196                         userDef.dataList.push( instance );\r
197                         userDef.userList.push( dataUser );\r
198                         instance.User = dataUser;\r
199                         def._tempUser = null;\r
200                 } else {\r
201                         def.live && def.live.push( instance );\r
202                 };\r
203                 if( def.Super ){\r
204                         // TODO klass.prototype に移動\r
205                         instance.Super = def.SuperProto;\r
206                         instance.SuperConstructor = superConstructor;\r
207                 };\r
208                 obj = def[ CONSTRUCTOR ] ?\r
209                                 def[ CONSTRUCTOR ].apply( instance, args ) :\r
210                         def.SuperConstructor &&\r
211                                 def.SuperConstructor.apply( instance, args );\r
212                 if( X.Type.isObject( obj ) && obj !== instance ){\r
213                         instance.kill();\r
214                         return obj;\r
215                 };\r
216                 return instance;\r
217         };\r
218         \r
219         function superConstructor(){\r
220                 var s = X.Class._getClassDef( this ).SuperConstructor;\r
221                 s && s.apply( this, arguments );\r
222         };\r
223         \r
224         return {\r
225                 POOL_OBJECT  : 1,\r
226                 ABSTRACT     : 2,\r
227                 FINAL        : 4,\r
228                 SUPER_ACCESS : 8,\r
229                 PRIVATE_DATA : 16,\r
230                 create : function( /* displayName, classSetting, opt_PrivateClass, props */ ){\r
231                         var args        = X.copyArray( arguments ),\r
232                                 displayName = args[ 0 ],\r
233                                 classSetting,\r
234                                 opt_pool, opt_abstract, opt_final, opt_private,\r
235                                 privateDef,\r
236                                 props,\r
237                                 klass,\r
238                                 classDef = {};\r
239                         if( X.Type.isString( displayName ) === true ){\r
240                                 classDef.displayName = displayName;\r
241                                 args.shift();\r
242                         };\r
243                         \r
244                         // クラス設定\r
245                         classDef.setting = classSetting = args[ 0 ];\r
246                         if( X.Type.isNumber( classSetting ) ){\r
247                                 opt_pool     = !!( classSetting & X.Class.POOL_OBJECT  );\r
248                                 opt_abstract = !!( classSetting & X.Class.ABSTRACT     );\r
249                                 opt_final    = !!( classSetting & X.Class.FINAL        );\r
250                                 opt_private  = !!( classSetting & X.Class.PRIVATE_DATA );\r
251                                 if( opt_final && opt_abstract ){\r
252                                         X.Notification.critical( 'final & Abstract!' );\r
253                                         return;\r
254                                 };      \r
255                                 args.shift();\r
256                         } else {\r
257                                 classDef.setting = 0;\r
258                         };\r
259                         \r
260                         // シャドウクラス\r
261                         if( PRIVATE_CLASS_LIST.indexOf( args[ 0 ] ) !== -1 ){\r
262                                 privateDef = X.Class._getClassDef( args[ 0 ] );\r
263                                 if( privateDef.isPrivate !== true ){\r
264                                         X.Notification.critical( 'PrivateClass not found! please, X.Class.create( X.Class.PRIVATE, {...} ).' );\r
265                                         return;\r
266                                 } else\r
267                                 if( privateDef.Abstract === true ){\r
268                                         X.Notification.critical( 'PrivateClass is Abstract!' );\r
269                                         return;\r
270                                 };\r
271                                 classDef.privateClass = args.shift();\r
272                         };\r
273                         \r
274                         // インスタンスのメンバー\r
275                         props = args[ 0 ];\r
276                         if( !X.Type.isObject( props ) ){\r
277                                 // サブクラスの場合、クラス定義の上書きがなくても作成可能\r
278                                 // サブクラスでなくても、クラスメンバ用オブジェクトが無しでも作成可能\r
279                                 //if( !traits ){\r
280                                 //      X.Notification.critical( 'No Class Def!' );\r
281                                 //      return;\r
282                                 //};\r
283                                 props = {};\r
284                         } else\r
285                         if( props[ CONSTRUCTOR ] && X.Type.isFunction( props[ CONSTRUCTOR ] ) ){\r
286                                 classDef[ CONSTRUCTOR ] = props[ CONSTRUCTOR ];\r
287                         };\r
288 \r
289                         klass = new Function( 'var a=arguments,f=a.callee;if(f.__new)return f.__new(a)' );\r
290                         klass.__new = C;\r
291                         klass.superClassOf = X.Class._superClassOf;\r
292                         klass.subClassOf   = X.Class._subClassOf;\r
293                         \r
294                         if( useObjectCreate ){\r
295                                 klass.prototype = X.Class._override( X.Class._override( traits || klass.prototype, props, true ), CommonProps, false );\r
296                                 klass.prototype.constructor = klass;\r
297                         } else\r
298                         if( use__proto__ ){\r
299                                 X.Class._override( klass.prototype, props, true );\r
300                                 if( traits ){\r
301                                         klass.prototype.__proto__ = traits;\r
302                                 } else {\r
303                                         X.Class._override( klass.prototype, CommonProps, false );\r
304                                 };\r
305                         } else {\r
306                                 klass.prototype = X.Class._override( X.Class._override( traits || klass.prototype, props, true ), CommonProps, false );\r
307                                 klass.prototype.constructor = klass;\r
308                         };\r
309                         klass.name = displayName;\r
310                         \r
311                         if( opt_abstract === true ){\r
312                                 classDef.Abstract = true;\r
313                         } else\r
314                         if( opt_pool === true ){\r
315                                 classDef.pool = [];\r
316                                 if( opt_private === false ) classDef.live = [];\r
317                         };                      \r
318                         if( opt_final === true ){\r
319                                 classDef.Final = true;\r
320                         } else {\r
321                                 klass.inherits = inherits;\r
322                         };                      \r
323                         if( opt_private === true ){\r
324                                 if( classDef.privateClass ){\r
325                                         X.Notification.critical( 'Private Data Class has no PrivateClass!' );\r
326                                         return;\r
327                                 };\r
328                                 classDef.isPrivate = true;\r
329                                 PRIVATE_CLASS_LIST.push( klass );\r
330                                 PRIVATE_DEF_LIST.push( classDef );\r
331                         } else {\r
332                                 CLASS_LIST.push( klass );\r
333                                 DEF_LIST.push( classDef );                              \r
334                         };\r
335                         return klass;\r
336                 },\r
337                 sys_shutdown : function(){\r
338                         \r
339                 },\r
340                 _getClass : function( instance ){\r
341                         var cList    = CLASS_LIST,\r
342                                 i        = cList.length,\r
343                                 klass;\r
344                         for( ; i; ){\r
345                                 klass = cList[ --i ];\r
346                                 if( instance.constructor === klass ) return klass;\r
347                         };\r
348                         cList = PRIVATE_CLASS_LIST;\r
349                         i     = cList.length;\r
350                         for( ; i; ){\r
351                                 klass = cList[ --i ];\r
352                                 if( instance.constructor === klass ) return klass;\r
353                         };\r
354                         \r
355                         if( cList.indexOf( instance ) !== -1 ) return instance;\r
356                         if( CLASS_LIST.indexOf( instance ) !== -1 ) return instance;\r
357                 },\r
358                 _getClassDef : function( KlassOrInstance ){\r
359                         var i = CLASS_LIST.indexOf( KlassOrInstance );\r
360                         if( i === -1 ) i = CLASS_LIST.indexOf( X.Class._getClass( KlassOrInstance ) );\r
361                         if( i !== -1 ) return DEF_LIST[ i ];\r
362                         \r
363                         i = PRIVATE_CLASS_LIST.indexOf( KlassOrInstance );\r
364                         if( i === -1 ) i = PRIVATE_CLASS_LIST.indexOf( X.Class._getClass( KlassOrInstance ) );\r
365                         if( i !== -1 ) return PRIVATE_DEF_LIST[ i ];\r
366                         \r
367                         if( DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance;\r
368                         if( PRIVATE_DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance;\r
369                 },\r
370                 _newPrivate : function( /* instance, args */ ){\r
371                         var args         = X.copyArray( arguments ),\r
372                                 user         = args.shift(),\r
373                                 def          = X.Class._getClassDef( user ),\r
374                                 privateClass = def.privateClass,\r
375                                 privateDef   = X.Class._getClassDef( privateClass ),\r
376                                 i            = -1;\r
377                         if( def.userList ){\r
378                                 i = def.userList.indexOf( user );\r
379                         } else {\r
380                                 def.userList = [];\r
381                                 def.dataList = [];\r
382                         };\r
383                         if( i !== -1 ){\r
384                                 X.Notification.critical( 'PrivateData already exist!' );\r
385                                 return;\r
386                         };\r
387                         if( privateDef._tempUser ){\r
388                                 X.Notification.critical( 'newPrivate を連続呼び出しされたところ破綻' );\r
389                                 return;\r
390                         };\r
391                         privateDef._tempUser = user;\r
392                         return privateClass.__new( args );\r
393                 },\r
394                 _getPrivate : function( instance ){\r
395                         var def = X.Class._getClassDef( instance ),\r
396                                 i   = def.userList.indexOf( instance );\r
397                         if( i !== -1 ) return def.dataList[ i ];\r
398                 },\r
399                 /* over のプロパティを target にコピーする.ただし target の プロパティが優先, force で解除 */\r
400                 _override : function ( target, src, force ){\r
401                         var p;\r
402                         for( p in src ){\r
403                                 if( p === 'Super' || p === 'SuperConstructor' || p === '__proto__' || p === 'prototype' || p === 'constructor' ){\r
404                                         X.Notification.critical( 'Super & SuperConstructor is reserved!' );\r
405                                         return;\r
406                                 };\r
407                                 if( force || target[ p ] === void 0 ){\r
408                                         target[ p ] = src[ p ];\r
409                                 };\r
410                         };\r
411                         return target;\r
412                 },\r
413                 _superClassOf : function(){\r
414                         \r
415                 },\r
416                 _subClassOf : function(){\r
417                         \r
418                 }\r
419         };\r
420 })();\r
421 \r
422 console.log( 'X.Core.Class' );\r