OSDN Git Service

543dbee94bf331f1065eb028f4382c350c2083ac
[pettanr/clientJs.git] / 0.6.x / js / 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                 _slice             = Array.prototype.slice;\r
21                 \r
22         function copyArray( list ){\r
23         //return _slice.call( list, 0 );\r
24         var i = list.length, ret = new Array( i );\r
25         for( ; i; ){\r
26                 ret[ --i ] = list[ i ];\r
27         };\r
28         return ret;\r
29         };\r
30         \r
31         /* サブクラスを作るメソッド  \r
32          * var subClass = superClass.inherits( ... ) \r
33          * http://d.hatena.ne.jp/m-hiyama/20051018/1129605002\r
34          */\r
35         function inherits( /* displayName, classSetting, opt_PrivateClass, props */ ){\r
36                 var args        = copyArray( arguments ),\r
37                         params      = [],\r
38                         Super       = this,\r
39                         superDef    = X.Class._getClassDef( Super ),\r
40                         displayName = args[ 0 ],\r
41                         classSetting,\r
42                         opt_super,\r
43                         klass, def;\r
44                 if( superDef.Final === true ) X.Notification.critical( 'X.Class inherits, Class is final!' );\r
45                 \r
46                 if( X.Type.isString( displayName ) === true ){\r
47                         args.shift();\r
48                 } else {\r
49                         displayName = 'SubClass of ' + superDef.displayName;\r
50                 };\r
51                 params.push( displayName );\r
52                 \r
53                 classSetting = args[ 0 ];\r
54                 if( X.Type.isNumber( classSetting ) === true ){\r
55                         if( superDef.isPrivate === true ) classSetting = classSetting | X.Class.PRIVATE_DATA;\r
56                         opt_super = !!( classSetting & X.Class.SUPER_ACCESS );\r
57                         params.push( classSetting );\r
58                         args.shift();\r
59                 };\r
60                 if( X.Class._getClass( args[ 0 ] ) ){\r
61                         params.push( args.shift() );\r
62                 } else\r
63                 if( superDef.privateClass ){\r
64                         params.push( superDef.privateClass );\r
65                 };\r
66                 params.push( args[ 0 ] ); /* props */\r
67                 Super.__new = null;\r
68                 traits = new Super();\r
69                 Super.__new = C;\r
70                 klass  = X.Class.create.apply( null, params );\r
71                 traits = null;\r
72                 if( opt_super === true ){\r
73                         def = X.Class._getClassDef( klass );\r
74                         def.Super = Super;\r
75                         def.SuperProto = Super.prototype;\r
76                         def.SuperConstructor = superDef[ CONSTRUCTOR ];\r
77                 };\r
78                 return klass;\r
79         };\r
80         \r
81         /* X.Class.create で作られたクラスのインスタンスが共通で備えるメソッド */\r
82         var CommonProps = {\r
83                 kill : function(){\r
84                         var instance = this,\r
85                                 klass    = X.Class._getClass( instance ),\r
86                                 def      = X.Class._getClassDef( klass ),\r
87                                 data, p, i;\r
88                         if( def.isPrivate === true && killPrivateFlag === false ){\r
89                                 X.Notification.critical( 'PrivateInstance.kill() work in PrivateUser.kill().' );\r
90                                 return;\r
91                         };\r
92                         killPrivateFlag = false; // onKill 内で PrivateInstance.kill() を防ぐため\r
93                         // onKill() === false の場合、kill のキャンセル\r
94                         // private      は false での キャンセル は無視される\r
95                         if( X.Type.isFunction( instance.onKill ) && instance.onKill() === false && !def.isPrivate ){\r
96                                 return;\r
97                         };\r
98                         for( p in instance ){\r
99                                 if( instance.hasOwnProperty && !instance.hasOwnProperty( p ) ) continue;\r
100                                 delete instance[ p ];\r
101                         };\r
102                         if( def.pool ){\r
103                                 def.live && def.live.splice( def.live.indexOf( instance ), 1 );\r
104                                 def.pool[ def.pool.length ] = instance;\r
105                         };\r
106                         if( def.privateClass ){\r
107                                 i = def.userList.indexOf( instance );\r
108                                 if( i !== -1 ){\r
109                                         data            = X.Class._getPrivate( instance );\r
110                                         killPrivateFlag = true;\r
111                                         data.kill();\r
112                                         def.dataList.splice( i, 1 );\r
113                                         def.userList.splice( i, 1 );\r
114                                 };\r
115                         };\r
116                 },\r
117                 instanceOf : function( klass ){\r
118                         var Super = this;\r
119                         if( this.constructor === klass ) return true;\r
120                         while( Super = X.Class._getClassDef( Super ).Super ){\r
121                                 if( Super === klass ) return true;\r
122                         };\r
123                         return false;\r
124                 }\r
125         };\r
126         \r
127         /*\r
128          * new の実体.コンストラクタの機能は instance.Constructor に書く.\r
129          * これにより pool された オブジェクト(破棄されたインスタンス) を再利用できる\r
130          */\r
131         /* Constructor Real for GeneralClass */\r
132         function C( args ){\r
133                 var klass    = this,\r
134                         def      = X.Class._getClassDef( klass ),\r
135                         dataUser = def._tempUser,\r
136                         instance,\r
137                         userDef;\r
138                 if( def.Abstract === true ){\r
139                         X.Notification.critical( 'AbstractClass!' );\r
140                         return;\r
141                 };\r
142                 if( def.isPrivate === true && dataUser === null ){\r
143                         X.Notification.critical( 'use myClass.newPrivate( instance, ...args )!' );\r
144                         return;\r
145                 };\r
146                 klass.__new = null;\r
147                 instance = def.pool && def.pool.length > 0 ? def.pool.pop() : new klass();\r
148                 klass.__new = C;\r
149                 if( def.isPrivate === true ){\r
150                         userDef = X.Class._getClassDef( dataUser );\r
151                         userDef.dataList.push( instance );\r
152                         userDef.userList.push( dataUser );\r
153                         instance.User = dataUser;\r
154                         def._tempUser = null;\r
155                 } else {\r
156                         def.live && def.live.push( instance );\r
157                 };\r
158                 if( def.Super ){\r
159                         // klass.prototype に移動\r
160                         instance.Super = def.SuperProto;\r
161                         instance.SuperConstructor = superConstructor;\r
162                 };\r
163                 def[ CONSTRUCTOR ] && def[ CONSTRUCTOR ].apply( instance, args );\r
164                 return instance;\r
165         };\r
166         \r
167         function superConstructor(){\r
168                 var s = X.Class._getClassDef( this ).SuperConstructor;\r
169                 s && s.apply( this, arguments );\r
170         };\r
171         \r
172         return {\r
173                 POOL_OBJECT  : 1,\r
174                 ABSTRACT     : 2,\r
175                 FINAL        : 4,\r
176                 SUPER_ACCESS : 8,\r
177                 PRIVATE_DATA : 16,\r
178                 create : function( /* displayName, classSetting, opt_PrivateClass, props */ ){\r
179                         var args        = copyArray( arguments ),\r
180                                 displayName = args[ 0 ],\r
181                                 classSetting,\r
182                                 opt_pool, opt_abstract, opt_final, opt_private,\r
183                                 privateDef,\r
184                                 props,\r
185                                 klass,\r
186                                 classDef = {};\r
187                         if( X.Type.isString( displayName ) === true ){\r
188                                 classDef.displayName = displayName;\r
189                                 args.shift();\r
190                         };\r
191                         classSetting = args[ 0 ];\r
192                         if( X.Type.isNumber( classSetting ) === true ){\r
193                                 opt_pool     = !!( classSetting & X.Class.POOL_OBJECT  );\r
194                                 opt_abstract = !!( classSetting & X.Class.ABSTRACT     );\r
195                                 opt_final    = !!( classSetting & X.Class.FINAL        );\r
196                                 opt_private  = !!( classSetting & X.Class.PRIVATE_DATA );\r
197                                 if( opt_final === true && opt_abstract === true ){\r
198                                         X.Notification.critical( 'final & Abstract!' );\r
199                                         return;\r
200                                 };                              \r
201                                 args.shift();\r
202                         };\r
203                         \r
204                         if( PRIVATE_CLASS_LIST.indexOf( args[ 0 ] ) !== -1 ){\r
205                                 privateDef = X.Class._getClassDef( args[ 0 ] );\r
206                                 if( privateDef.isPrivate !== true ){\r
207                                         X.Notification.critical( 'PrivateClass not found! please, X.Class.create( X.Class.PRIVATE, {...} ).' );\r
208                                         return;\r
209                                 } else\r
210                                 if( privateDef.Abstract === true ){\r
211                                         X.Notification.critical( 'PrivateClass is Abstract!' );\r
212                                         return;\r
213                                 };\r
214                                 classDef.privateClass = args.shift();\r
215                         };\r
216                         props = args[ 0 ];\r
217                         if( props === null || X.Type.isObject( props ) === false ){\r
218                                 X.Notification.critical( 'No Class Def!' );\r
219                                 return;\r
220                         };\r
221                         \r
222                         if( props[ CONSTRUCTOR ] && X.Type.isFunction( props[ CONSTRUCTOR ] ) === true ){\r
223                                 classDef[ CONSTRUCTOR ] = props[ CONSTRUCTOR ];\r
224                         };\r
225                         \r
226                         klass = new Function( 'var a=arguments,f=a.callee;if(f.__new)return f.__new(a)' );\r
227                         klass.__new = C;\r
228                         klass.prototype = X.Class._override( X.Class._override( traits || klass.prototype, props, true ), CommonProps, false );\r
229                         klass.prototype.constructor = klass;\r
230                         klass.name = displayName;\r
231                         \r
232                         if( opt_abstract === true ){\r
233                                 classDef.Abstract = true;\r
234                         } else\r
235                         if( opt_pool === true ){\r
236                                 classDef.pool = [];\r
237                                 if( opt_private === false ) classDef.live = [];\r
238                         };                      \r
239                         if( opt_final === true ){\r
240                                 classDef.Final = true;\r
241                         } else {\r
242                                 klass.inherits = inherits;\r
243                         };                      \r
244                         if( opt_private === true ){\r
245                                 if( classDef.privateClass ){\r
246                                         X.Notification.critical( 'Private Data Class has no PrivateClass!' );\r
247                                         return;\r
248                                 };\r
249                                 classDef.isPrivate = true;\r
250                                 PRIVATE_CLASS_LIST.push( klass );\r
251                                 PRIVATE_DEF_LIST.push( classDef );\r
252                         } else {\r
253                                 CLASS_LIST.push( klass );\r
254                                 DEF_LIST.push( classDef );                              \r
255                         };\r
256                         return klass;\r
257                 },\r
258                 sys_shutdown : function(){\r
259                         \r
260                 },\r
261                 _getClass : function( instance ){\r
262                         var cList    = CLASS_LIST,\r
263                                 i        = cList.length,\r
264                                 klass;\r
265                         for( ; i; ){\r
266                                 klass = cList[ --i ];\r
267                                 if( instance.constructor === klass ) return klass;\r
268                         };\r
269                         cList = PRIVATE_CLASS_LIST;\r
270                         i     = cList.length;\r
271                         for( ; i; ){\r
272                                 klass = cList[ --i ];\r
273                                 if( instance.constructor === klass ) return klass;\r
274                         };\r
275                         \r
276                         if( cList.indexOf( instance ) !== -1 ) return instance;\r
277                         if( CLASS_LIST.indexOf( instance ) !== -1 ) return instance;\r
278                 },\r
279                 _getClassDef : function( KlassOrInstance ){\r
280                         var i = CLASS_LIST.indexOf( KlassOrInstance );\r
281                         if( i === -1 ) i = CLASS_LIST.indexOf( X.Class._getClass( KlassOrInstance ) );\r
282                         if( i !== -1 ) return DEF_LIST[ i ];\r
283                         \r
284                         i = PRIVATE_CLASS_LIST.indexOf( KlassOrInstance );\r
285                         if( i === -1 ) i = PRIVATE_CLASS_LIST.indexOf( X.Class._getClass( KlassOrInstance ) );\r
286                         if( i !== -1 ) return PRIVATE_DEF_LIST[ i ];\r
287                         \r
288                         if( DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance;\r
289                         if( PRIVATE_DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance;\r
290                 },\r
291                 _newPrivate : function( /* instance, args */ ){\r
292                         var args         = copyArray( arguments ),\r
293                                 user         = args.shift(),\r
294                                 def          = X.Class._getClassDef( user ),\r
295                                 privateClass = def.privateClass,\r
296                                 privateDef   = X.Class._getClassDef( privateClass ),\r
297                                 i            = -1;\r
298                         if( def.userList ){\r
299                                 i = def.userList.indexOf( user );\r
300                         } else {\r
301                                 def.userList = [];\r
302                                 def.dataList = [];\r
303                         };\r
304                         if( i !== -1 ){\r
305                                 X.Notification.critical( 'PrivateData already exist!' );\r
306                                 return;\r
307                         };\r
308                         if( privateDef._tempUser ){\r
309                                 X.Notification.critical( 'newPrivate を連続呼び出しされたところ破綻' );\r
310                                 return;\r
311                         };\r
312                         privateDef._tempUser = user;\r
313                         return privateClass.__new( args );\r
314                 },\r
315                 _getPrivate : function( instance ){\r
316                         var def = X.Class._getClassDef( instance ),\r
317                                 i   = def.userList.indexOf( instance );\r
318                         if( i !== -1 ) return def.dataList[ i ];\r
319                 },\r
320                 /* over のプロパティを target にコピーする.ただし target の プロパティが優先, force で解除 */\r
321                 _override : function ( target, src, force ){\r
322                         for( var p in src ){\r
323                                 if( p === 'Super' || p === 'SuperConstructor' ){\r
324                                         X.Notification.critical( 'Super & SuperConstructor is reserved!' );\r
325                                         return;\r
326                                 };\r
327                                 if( force === true || target[ p ] === void 0 ){\r
328                                         target[ p ] = src[ p ];\r
329                                 };\r
330                         };\r
331                         return target;\r
332                 }\r
333         };\r
334 })();