Facade.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. --[[
  2. * @author PureMVC Lua Native Port by Sean
  3. * @author Copyright(c) 2006-2012 Futurescale, Inc., Some rights reserved.
  4. *
  5. * @class puremvc.Facade
  6. * Facade exposes the functionality of the Controller, Model and View
  7. * actors to client facing code.
  8. *
  9. * This Facade implementation is a Multiton, so you should not call the
  10. * constructor directly, but instead call the static Factory method,
  11. * passing the unique key for this instance to #getInstance
  12. *
  13. * @constructor
  14. * @param {string} key
  15. * The multiton key to use to retrieve the Facade instance.
  16. * @throws {Error}
  17. * If an attempt is made to instantiate Facade directly
  18. ]]
  19. local Controller = require( framework.PACKAGE_NAME .. '/core/Controller')
  20. local Model = require( framework.PACKAGE_NAME .. '/core/Model')
  21. local View = require( framework.PACKAGE_NAME .. '/core/View')
  22. local Notification = require( framework.PACKAGE_NAME .. '/patterns/observer/Notification')
  23. local Facade = class("Facade")
  24. function Facade:ctor(key)
  25. if Facade.instanceMap[key] ~= nil then
  26. error(Facade.MULTITON_MSG)
  27. end
  28. self:initializeNotifier(key)
  29. Facade.instanceMap[key] = self
  30. self:initializeFacade()
  31. end
  32. --[[
  33. * Initialize the Multiton Facade instance.
  34. *
  35. * Called automatically by the constructor. Override in your subclass to any
  36. * subclass specific initializations. Be sure to call the 'super'
  37. * initializeFacade method, though
  38. *
  39. * MyFacade.prototype.initializeFacade= function ()
  40. * {
  41. * Facade.call(this);
  42. * };
  43. * @protected
  44. * @return {void}
  45. ]]
  46. function Facade:initializeFacade()
  47. self:initializeModel();
  48. self:initializeController();
  49. self:initializeView();
  50. end
  51. --[[
  52. * Facade Multiton Factory method.
  53. * Note that this method will return null if supplied a
  54. * null or undefined multiton key.
  55. *
  56. * @param {string} key
  57. * The multiton key use to retrieve a particular Facade instance
  58. * @return {puremvc.Facade}
  59. ]]
  60. function Facade.getInstance(key)
  61. if nil == key then
  62. return nil
  63. end
  64. if Facade.instanceMap[key] == nil then
  65. Facade.instanceMap[key] = Facade.new(key)
  66. end
  67. return Facade.instanceMap[key]
  68. end
  69. --[[
  70. * Initialize the {@link puremvc.Controller Controller}.
  71. *
  72. * Called by the #initializeFacade method.
  73. *
  74. * Override this method in your subclass of Facade
  75. * if one or both of the following are true:
  76. * - You wish to initialize a different Controller
  77. * - You have
  78. * {@link puremvc.SimpleCommand SimpleCommand}s
  79. * or {@link puremvc.MacroCommand MacroCommand}s
  80. * to register with the Controllerat startup.
  81. *
  82. * If you don't want to initialize a different Controller,
  83. * call the 'super' initializeControlle method at the beginning of your
  84. * method, then register commands.
  85. *
  86. * MyFacade.prototype.initializeController= function ()
  87. * {
  88. * Facade.prototype.initializeController.call(this);
  89. * this.registerCommand(AppConstants.A_NOTE_NAME, ABespokeCommand)
  90. * }
  91. *
  92. * @protected
  93. * @return {void}
  94. ]]
  95. function Facade:initializeController()
  96. if self.controller ~= nil then
  97. return
  98. end
  99. self.controller = Controller.getInstance(self.multitonKey);
  100. end
  101. --[[
  102. * @protected
  103. * Initialize the {@link puremvc.Model Model};
  104. *
  105. * Called by the #initializeFacade method.
  106. * Override this method in your subclass of Facade if one of the following are
  107. * true:
  108. *
  109. * - You wish to initialize a different Model.
  110. *
  111. * - You have {@link puremvc.Proxy Proxy}s to
  112. * register with the Model that do not retrieve a reference to the Facade at
  113. * construction time.
  114. *
  115. * If you don't want to initialize a different Model
  116. * call 'super' #initializeModel at the beginning of your method, then register
  117. * Proxys.
  118. *
  119. * Note: This method is *rarely* overridden; in practice you are more
  120. * likely to use a command to create and registerProxys with the Model>,
  121. * since Proxys with mutable data will likely
  122. * need to send Notifications and thus will likely want to fetch a reference to
  123. * the Facade during their construction.
  124. *
  125. * @return {void}
  126. ]]
  127. function Facade:initializeModel()
  128. if self.model ~= nil then
  129. return
  130. end
  131. self.model = Model.getInstance(self.multitonKey)
  132. end
  133. --[[
  134. * @protected
  135. *
  136. * Initialize the {@link puremvc.View View}.
  137. *
  138. * Called by the #initializeFacade method.
  139. *
  140. * Override this method in your subclass of Facade if one or both of the
  141. * following are true:
  142. *
  143. * - You wish to initialize a different View.
  144. * - You have Observers to register with the View
  145. *
  146. * If you don't want to initialize a different View
  147. * call 'super' #initializeView at the beginning of your
  148. * method, then register Mediator instances.
  149. *
  150. * MyFacade.prototype.initializeView= function ()
  151. * {
  152. * Facade.prototype.initializeView.call(this);
  153. * this.registerMediator(new MyMediator());
  154. * };
  155. *
  156. * Note: This method is *rarely* overridden; in practice you are more
  157. * likely to use a command to create and register Mediators
  158. * with the View, since Mediator instances will need to send
  159. * Notifications and thus will likely want to fetch a reference
  160. * to the Facade during their construction.
  161. * @return {void}
  162. ]]
  163. function Facade:initializeView()
  164. if self.view ~= nil then
  165. return
  166. end
  167. self.view = View.getInstance(self.multitonKey)
  168. end
  169. --[[
  170. * Register a command with the Controller by Notification name
  171. * @param {string} notificationName
  172. * The name of the Notification to associate the command with
  173. * @param {Function} commandClassRef
  174. * A reference ot the commands constructor.
  175. * @return {void}
  176. ]]
  177. function Facade:registerCommand(notificationName, commandClassRef)
  178. self.controller:registerCommand(notificationName, commandClassRef)
  179. end
  180. --[[
  181. * Remove a previously registered command to Notification mapping from the
  182. * {@link puremvc.Controller#removeCommand Controller}
  183. * @param {string} notificationName
  184. * The name of the the Notification to remove from the command mapping for.
  185. * @return {void}
  186. ]]
  187. function Facade:removeCommand(notificationName)
  188. self.controller:removeCommand(notificationName)
  189. end
  190. --[[
  191. * Check if a command is registered for a given notification.
  192. *
  193. * @param {string} notificationName
  194. * A Notification name
  195. * @return {boolean}
  196. * Whether a comman is currently registered for the given notificationName
  197. ]]
  198. function Facade:hasCommand(notificationName)
  199. return self.controller:hasCommand(notificationName)
  200. end
  201. --[[
  202. * Register a Proxy with the {@link puremvc.Model#registerProxy Model}
  203. * by name.
  204. *
  205. * @param {puremvc.Proxy} proxy
  206. * The Proxy instance to be registered with the Model.
  207. * @return {void}
  208. ]]
  209. function Facade:registerProxy(proxy)
  210. self.model:registerProxy(proxy)
  211. end
  212. --[[
  213. * Retrieve a Proxy from the Model
  214. *
  215. * @param {string} proxyName
  216. * @return {puremvc.Proxy}
  217. ]]
  218. function Facade:retrieveProxy(proxyName)
  219. return self.model:retrieveProxy(proxyName)
  220. end
  221. --[[
  222. * Remove a Proxy from the Model by name
  223. * @param {string} proxyName
  224. * The name of the Proxy
  225. * @return {puremvc.Proxy}
  226. * The Proxy that was removed from the Model
  227. ]]
  228. function Facade:removeProxy(proxyName)
  229. local proxy = nil
  230. if self.model ~= nil then
  231. proxy = self.model:removeProxy(proxyName)
  232. end
  233. return proxy
  234. end
  235. --[[
  236. * Check it a Proxy is registered.
  237. * @param {string} proxyName
  238. * A Proxy name
  239. * @return {boolean}
  240. * Whether a Proxy is currently registered with the given proxyName
  241. ]]
  242. function Facade:hasProxy(proxyName)
  243. return self.model:hasProxy(proxyName)
  244. end
  245. --[[
  246. * Register a Mediator with with the View.
  247. *
  248. * @param {puremvc.Mediator} mediator
  249. * A reference to the Mediator to register
  250. * @return {void}
  251. ]]
  252. function Facade:registerMediator(mediator)
  253. if self.view ~= nil then
  254. self.view:registerMediator(mediator)
  255. end
  256. end
  257. --[[
  258. * Retrieve a Mediator from the View by name
  259. *
  260. * @param {string} mediatorName
  261. * The Mediators name
  262. * @return {puremvc.Mediator}
  263. * The retrieved Mediator
  264. ]]
  265. function Facade:retrieveMediator(mediatorName)
  266. return self.view:retrieveMediator(mediatorName)
  267. end
  268. --[[
  269. * Remove a Mediator from the View.
  270. *
  271. * @param {string} mediatorName
  272. * The name of the Mediator to remove.
  273. * @return {puremvc.Mediator}
  274. * The removed Mediator
  275. ]]
  276. function Facade:removeMediator(mediatorName)
  277. local mediator = nil
  278. if self.view ~= nil then
  279. mediator = self.view:removeMediator(mediatorName)
  280. end
  281. return mediator
  282. end
  283. --[[
  284. * Check if a Mediator is registered or not.
  285. *
  286. * @param {string} mediatorName
  287. * A Mediator name
  288. * @return {boolean}
  289. * Whether a Mediator is registered with the given mediatorName
  290. ]]
  291. function Facade:hasMediator(mediatorName)
  292. return self.view:hasMediator(mediatorName)
  293. end
  294. --[[
  295. * Create and send a
  296. * {@link puremvc.Notification Notification}
  297. *
  298. * Keeps us from having to construct new Notification instances in our
  299. * implementation
  300. *
  301. * @param {string} notificationName
  302. * The name of the Notification to send
  303. * @param {Object} [body]
  304. * The body of the notification
  305. * @param {string} [type]
  306. * The type of the notification
  307. * @return {void}
  308. ]]
  309. function Facade:sendNotification(notificationName, body, type)
  310. self:notifyObservers(Notification.new(notificationName, body, type))
  311. end
  312. --[[
  313. * Notify {@link puremvc.Observer Observer}s
  314. *
  315. * This method is left public mostly for backward compatibility, and to allow
  316. * you to send custom notification classes using the facade.
  317. *
  318. * Usually you should just call sendNotification and pass the parameters, never
  319. * having to construct the notification yourself.
  320. *
  321. * @param {puremvc.Notification} notification
  322. * The Notification to send
  323. * @return {void}
  324. ]]
  325. function Facade:notifyObservers(notification)
  326. if self.view ~= nil then
  327. self.view:notifyObservers(notification)
  328. end
  329. end
  330. --[[
  331. * Initialize the Facades Notifier capabilities by setting the Multiton key for
  332. * this facade instance.
  333. *
  334. * Not called directly, but instead from the constructor when #getInstance is
  335. * invoked. It is necessary to be public in order to implement Notifier
  336. *
  337. * @param {string} key
  338. * @return {void}
  339. ]]
  340. function Facade:initializeNotifier(key)
  341. self.multitonKey = key
  342. end
  343. --[[
  344. * Check if a *Core* is registered or not
  345. *
  346. * @static
  347. * @param {string} key
  348. * The multiton key for the *Core* in question
  349. * @return {boolean}
  350. * Whether a *Core* is registered with the given key
  351. ]]
  352. function Facade.hasCore(key)
  353. return Facade.instanceMap[key] ~= nil
  354. end
  355. --[[
  356. * Remove a *Core*
  357. *
  358. * Remove the Model, View, Controller and Facade for a given key.
  359. *
  360. * @static
  361. * @param {string} key
  362. * @return {void}
  363. ]]
  364. function Facade.removeCore(key)
  365. if Facade.instanceMap[key] == nil then
  366. return
  367. end
  368. Model.removeModel(key)
  369. View.removeView(key)
  370. Controller.removeController(key)
  371. Facade.instanceMap[key] = nil
  372. end
  373. --[[
  374. * @ignore
  375. * The Multiton Facade instance map.
  376. * @static
  377. * @protected
  378. * @type Array
  379. ]]
  380. Facade.instanceMap = {}
  381. --[[
  382. * @ignore
  383. * Message Constants
  384. * @protected
  385. * @type {string}
  386. * @const
  387. * @static
  388. ]]
  389. Facade.MULTITON_MSG = "Facade instance for this Multiton key already constructed!";
  390. return Facade