Should I (and how to) avoid "forests" of listeners in nested OOP structure.

2 views (last 30 days)
Cedric Wannaz
Cedric Wannaz on 18 Dec 2017
Edited: Cedric Wannaz on 19 Dec 2017
Dear all,
System < handle, with properties System.grids and System.result
Grid < handle, with property Grid.layers
Layer < handle, with property Layer.gridCells
GridCell < handle, with property GridCell.area
where each class implements a property that is a cell array of objects of the class "below", i.e. System.grids={Grid obj #1,..}, Grid.layers={Layer obj #1,..} and Layer.gridCells={GridCell obj #1,..}. Property System.result is built/computed for a specific set of grids (and hence layers and grid cells). Its value must therefore be updated each time a grid or one the grids' layer or one of the layers' cell is updated (e.g. the area). EDIT 1 - If:
gc = system.grids{2}.layers{10}.gridCells{15200} ;
the following:
gc.area = 147 ;
should trigger an update of system.result.
In a less nested context, e.g. if updating a grid would be done through a basic set access to System.grids such as:
system.grids{3} = newGrid ;
I could manage triggering the update of result through a setter for the grids property. In a little more nested context, e.g. if layers can be updated without replacing Grid objects, through:
system.grids{3}.layers{1} = newLayer ;
I could set the layers property of Grid observable:
classdef Grid < handle
properties( SetObservable = true )
an add listeners to the System object bound to each grid layers property and to the 'PostSet' event. Or better, I can define an event 'updated' in each class Grid, Layer, and GridCell, that would back-propagated to the System object through a chain of listeners: EDIT 2017/12/19 @ 19:30 UTC, e.g.:
classdef Grid < Cascadable
function obj = Grid()
obj = obj@Cascadable() ;
function addLayer( obj, layer )
obj.layers{end+1} = layer ;
addlistener( layer, 'updated', ...
@(src, evnt) eventHandler_updated( obj, src, evnt )) ;
obj.eventHandler_updated() ;
classdef Cascadable < handle
function obj = Cascadable()
function eventHandler_updated( obj, varargin )
fprintf( '%s updated\n', class( obj )) ;
obj.notify( 'updated' ) ;
and an event handler in System that does a little more work, e.g. recomputing result.
While this last approach seems to be "clean enough", it requires adding setters that call NOTIFY for all relevant properties in each class, or overloading SUBSASGN for that purpose, or defining 'PostSet' listeners for all relevant properties of "self" (just for avoiding implementing a lot a setters and instead defining a single event handling method for all properties). This seems to be cumbersome and to defeat the purpose of events/listeners.
Is there a cleaner way? Did I miss an important mechanism, like a 'CascadedPostSet' event?

Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!