I drew this idea from the introduction to the book Object-Oriented Design. Design patterns from the "gang of four." It says that all pointers to objects are divided into two types: aggregation and awareness. Awareness means that the object that owns the pointer does not bear any responsibility for the object to which it refers. He simply has access to his public fields and methods, but the lifetime of this object is not under his control. Aggregation means that the object owning the link is responsible for the destruction of the object to which it refers. As a rule, an aggregated object lives while the owner object is alive, although there are more complex cases.
In jWidget, the aggregation is implemented through the own method of the JW.Class class. By passing object B to object A's own method, you made object A to own object B. When object A is destroyed, object B will be destroyed automatically. For convenience, the own method returns object B.
var Book = function() { Book._super.call(this); this.cover = this.own(new Cover()); }; JW.extend(Book, JW.Class, { destroyObject: function() { console.log("Destroying book"); this._super(); } }); var Cover = function() { Cover._super.call(this); }; JW.extend(Cover, JW.Class, { destroyObject: function() { console.log("Destroying cover"); this._super(); } });
var book = new Book(); book.destroy(); // : // Destroying cover // Destroying book
var MyView = function() { MyView._super.call(this); $(window).resize(JW.inScope(this._layout, this)); }; JW.extend(MyView, JW.Class, { _layout: function() { // ... } });
var view = new MyView(); view.destroy();
var MyView = function() { MyView._super.call(this); $(window).bind("resize", JW.inScope(this._layout, this)); }; JW.extend(MyView, JW.Class, { _layout: function() { // ... }, destroyObject: function() { $(window).unbind("resize", JW.inScope(this._layout, this)); this._super(); } });
var MyView = function() { this._layout = JW.inScope(this._layout, this); MyView._super.call(this); $(window).bind("resize", this._layout); }; JW.extend(MyView, JW.Class, { _layout: function() { // ... }, destroyObject: function() { $(window).unbind("resize", this._layout); this._super(); } });
var MyView = function() { MyView._super.call(this); this.own($(window).jwon("resize", this._layout, this)); }; JW.extend(MyView, JW.Class, { _layout: function() { // ... } });
var property = new JW.Property().ownValue(); property.set(new SampleValue(1)); property.set(new SampleValue(2)); // SampleValue(1) property.destroy(); // SampleValue(2)
var array = new JW.Array().ownItems(); array.add(new SampleValue(1)); array.add(new SampleValue(2)); array.set(new SampleValue(3), 0); // SampleValue(1) array.remove(1); // SampleValue(2) array.destroy(); // SampleValue(3)
var MyView = function(event) { MyView._super.call(this); this.content = null; this.initContent(); this.own(event.bind(this.refreshContent, this)); }; JW.extend(MyView, JW.Class, { destroyObject: function() { this.doneContent(); this._super(); }, initContent: function() { this.content = new Content(); }, doneContent: function() { this.content.destroy(); }, refreshContent: function() { this.doneContent(); this.initContent(); } });
var MyView = function(event) { MyView._super.call(this); this.content = this.own(new JW.Property()).ownValue(); // this.refreshContent(); this.own(event.bind(this.refreshContent, this)); }; JW.extend(MyView, JW.Class, { refreshContent: function() { this.content.set(new Content()); } });
refreshContent: function() { this.content.set(null); this.content.set(new Content()); }
var MyPage = function() { MyPage._super.call(this); this.currentOperation = this.own(new JW.Property()).ownValue(); // this.dataHunkIndex = 0; }; JW.extend(MyPage, JW.UI.Component, { afterRender: function() { this._super(); this._loadData(); }, _loadData: function() { this.currentOperation.set(new Request("/api/data", {hunk: this.dataHunkIndex}, this._onDataLoad, this)); }, _onDataLoad: function(result) { this.currentOperation.set(new Animation("fade in", this._onAnimationFinish, this)); }, _onAnimationFinish: function() { this.currentOperation.set(null); }, renderLoadNextHunkButton: function(el) { el.jwon("click", this._loadNextHunk, this); }, _loadNextHunk: function() { ++this.dataHunkIndex; this._loadData(); } });
var Request = function(url, data, success, scope) { Request._super.call(this); this.aborted = false; this.success = success; this.scope = scope; this.ajax = $.ajax({ url : url, data : data, success : this._onSuccess, error : this._onError, context : this }); }; JW.extend(Request, JW.Class, { destroyObject: function() { // "abort" jQuery , // . this.aborted = true; // , "abort" . // - this.ajax.abort(); this._super(); }, _onSuccess: function(result) { this.success.call(this.scope, result); }, _onError: function() { if (!this.aborted) { alert("Request has failed =(("); } } });
var Client = function(event, factory) { Client._super.call(this); this.factory = factory; this.objects = null; // Array this.initObjects(); this.own(event.bind(this.refreshObjects, this)); }; JW.extend(Client, JW.Class, { destroyObject: function() { this.doneObjects(); this._super(); }, initObjects: function() { this.objects = this.factory.createObjects(); }, doneObjects: function() { for (var i = this.objects.length - 1; i >= 0; --i) { this.objects[i].destroy(); } this.objects = null; }, refreshObjects: function() { this.doneObjects(); this.initObjects(); } }); var Factory = { createObjects: function() { return [ new Object1(), new Object2(), new Object3() ]; } };
var Client = function(event, factory) { Client._super.call(this); this.factory = factory; this.objects = this.own(new JW.Property()).ownValue(); this.refreshObjects(); this.own(event.bind(this.refreshObjects, this)); }; JW.extend(Client, JW.Class, { refreshObjects: function() { this.objects.set(this.factory.createObjects()); } }); var Factory = { createObjects: function() { // var objects = new JW.Class(); objects.own(new Object1()); objects.own(new Object2()); objects.own(new Object3()); return objects; } };
var ColorDriver = function(selectedScheme, colorKey, color) { ColorDriver._super.call(this); this.selectedScheme = selectedScheme; // JW.Property<Dictionary> this.colorKey = colorKey; // color this.color = color || this.own(new JW.Property()); this._update(); this.own(this.selectedScheme.changeEvent.bind(this._update, this)); }; JW.extend(ColorDriver, JW.Class, { _update: function() { this.color.set(this.selectedScheme.get()[this.colorKey]); } });
var ColorSchemeManager = function() { ColorSchemeManager._super.call(this); this.selectedScheme = this.own(new JW.Property()); }; JW.extend(ColorSchemeManager, JW.Class, { getColorDriver: function(key) { return new ColorDriver(this.selectedScheme, key); } });
var Client = function(colorSchemeManager) { Client._super.call(this): this.colorSchemeManager = colorSchemeManager; }; JW.extend(Client, JW.UI.Component, { renderBackground: function(el) { var color = this.own(this.colorSchemeManager.getColorDriver("background")).color; this.own(el.jwcss("background-color", color)); } });
var ColorSchemeManager = function() { ColorSchemeManager._super.call(this); this.selectedScheme = this.own(new JW.Property()); }; JW.extend(ColorSchemeManager, JW.Class, { getColor: function(key) { // var color = new JW.Property(); color.own(new ColorDriver(this.selectedScheme, key, color)); return color; } }); var Client = function(colorSchemeManager) { Client._super.call(this): this.colorSchemeManager = colorSchemeManager; }; JW.extend(Client, JW.UI.Component, { renderBackground: function(el) { var color = this.own(this.colorSchemeManager.getColor("background")); this.own(el.jwcss("background-color", color)); } });
Source: https://habr.com/ru/post/270879/
All Articles