Order of instantiation & Events

Say I have a class A which has an Event "event1" which class B needs to listen for. I want class B to also be a property of class A, ie. I can instantiate obj = A(B). Ideally, in this process B would be set to listen for "event1" from A, but since Matlab builds B first, it does not know anything about A, and thus it has to be done effectively during the instantiation of A. The more complicated version is A(B(C)), where once again C needs to listen for "event1" in A, but is a property of B, which is a property of A.
In a nutshell I have an object A which is supplying the base data to a process which can involve anywhere from one to multiple filters, which is acted on and ultimately passed back to A... so the initial data needs to go to the bottom filter... the filters are defined by classes, in order to be portable and used in different situations..
The question, is there an efficient way to either define the classes or to instantiate the classes that would allow me to have the inner most nested class listen to the Event "event1" in the outer class without having to build a bunch of conditionals in the outer class instantiation function.

9 Comments

Adam
Adam on 4 Jan 2017
Edited: Adam on 4 Jan 2017
An object having to listen to an event triggered from the object that contains it sounds like slightly suspicious design though. If A owns B anyway why doesn't it just directly trigger what would otherwise be triggered by the event? Then B doesn't need to have knowledge of A. I don't mean necessarily right in the function that would trigger the event as that would also be bad design, but you can inject a callback (or as many callbacks as you want) into that function that will get called when you would otherwise fire off the event. That callback could be either a direct function on B or a function on A that calls the function on B.
I'm with Adam, something does not sound right here. I don't see why B needs to listen to A, when A could just inform B straight away.
Maybe you should explain your use case in more details. What is the relevant interface of B and A? Are all the filters derived from an abstract class?
Struggling a bit in how to describe what's going on in a brief manner....So I have a Class which defines an object which supplies data in discrete increments via a Notify. Assume this is market data like stock prices. Then there are various filter objects which can act on that data, transform it is some way, and return the result. One might want to use a single filter on the data, or apply another filter to the already filtered data, and so on... in some cases there could be 4-5 separate transforms. In the end, the outside object uses the final filtered set of data to feed another function. So the outside function supplies the initial set of data, and then has to get back the final filtered output, subject to this somewhat recursive process. The idea is to keep it modular, and be able to modify the filter choices yet be able to reuse the more generic outside object. Hope that helps... and I am aware I may just be coding this poorly...
Adam
Adam on 5 Jan 2017
Edited: Adam on 5 Jan 2017
It would probably help if you could give a simple code example of the structure. I would say that the object that supplies data should not be owning objects that want to act upon that data in specific ways, as a general rule.
I have many areas in my code where I have classes that need to act on some changeable data and within these classes I inject a 'data provider' object which is responsible for supplying the data to the e.g. calculator class.
In terms of how the messaging is designed I have done this in numerous different ways, depending on where I want to drive the actions from and what it is that triggers the data to change. If the 'data provider' is responsible for choosing what data to provide and when then it can send out notifications when this data changes and the calculator/filter classes into which it has been injected can then respond to this in whatever way they choose and update their calculations, possibly then sending out a notification themselves for any further part of the program which wishes to respond to this - e.g. your multiple layers of transforms.
In other places my data provider plays no part in the communications and some other object is responsible for letting components know that something has changed so that those components (calculators/filters/transforms) must re-query the data provider object for the latest data to use.
The basic idea though is of reversing the chain of messaging from what you seem to have. An object should never really be wanting to know about its parent. Instead that would-be 'parent' object should be injected into the other object for it to use and then that object is listening to one of the properties it owns (or has a reference to) rather than needing to know what owns it and listen to that.
Adam... thanks for your thoughts... I went ahead and did exactly what you say at the bottom, just reversed the inputs such that the bottom object gets built first, which makes the instantiation process pretty easy and clean... and then the challenge becomes getting the final filtered answer back to the original object, which I just created a separate notification process which passed the final answer back to the top. Thanks again for comments.
In the interest of being complete, here are 3 classes, the main ones being outerClass and childClass... eventDataClass just passes data thru the Notify event. This can be called in the following manner
Obj = outerClass(10,childClass); ....
or a very nested, recursive version Obj = outerClass(10,childClass(childClass(childClass)));
childClass just takes the data passed to it, and multiplies it by .5 ....
So the question now is if outerClass needs the final result of all the filtering... i.e. the innermost value of childClass.output.. what is the best way to either reference that object, or pass it back??
Right now outerClass.output just returns outerClass.child.output... but if there are nested versions of childClass, it will not get those further values
classdef outerClass < handle
properties
data
child
end
properties (Dependent)
output
end
events
event1
end
methods
function obj = outerClass(data,child)
obj.data = data;
obj.child = child;
addlistener(obj,'event1',@(src,evnt) child.dataUpdate(src,evnt));
end
function feedData(obj)
T = size(obj.data,1);
for t = 1:T
notify(obj,'event1',eventDataClass(obj.data(t)));
end
end
function value = get.output(obj)
value = obj.child.output;
end
end
end
classdef childClass < handle
properties
child = []
end
properties (SetAccess = private)
data
end
properties (Dependent)
output
end
events
event1
end
methods
function obj = childClass(child)
if nargin==1
obj.child = child;
addlistener(obj,'event1',@(src,evnt) obj.child.dataUpdate(src,evnt));
end
end
function dataUpdate(obj,~,evnt)
obj.data = evnt.newData;
if any(event.hasListener(obj,'event1'))
notify(obj,'event1',eventDataClass(obj.output));
end
end
function value = get.output(obj)
value = obj.data*.5;
end
end
end
classdef (ConstructOnLoad) eventDataClass < event.EventData
properties
newData = [];
end
methods
function eventData = eventDataClass (newData)
eventData.newData = newData;
end
end
end
I'm not sure I get what is happening with the recursive children here. Each one has the same copy of updated data and each one will multiply it by 0.5.
But what is the expected result of all this if, for example, there are 3 nested children. As it stands you will just get the result of the top-most child, but the result of all child objects will be the same anyway as they are all acting on the same data.
I assumed the intention was for them to act upon each other's results back up the chain, but this doesn't seem to be the setup you have because the 'data' field is just the same data being passed to each child.
If the child objects are to act upon the result of the next one down the chain then the 'data' of children higher up the chain needs to be the result of obj.child.output, which will then get multiplied by 0.5.
If this is the case then the final result you want will be in the child immediately below the parent object and would be the result of effectively, e.g 0.5 * 0.5 * 0.5 * data rather than just 0.5 * data.
That is what is happening Adam... the 'data' into each child is the output of the one above... they are not getting the same original data.

Sign in to comment.

 Accepted Answer

Guillaume
Guillaume on 6 Jan 2017
Edited: Guillaume on 6 Jan 2017
I really don't understand the point of objects listening to their own events. Why not invoke the dataupdate method of the child directly in the feeddata method?
With the current design, the child class has two roles: - filter the data, - incomplete management of a singly linked list, with dispatch to elements. While this is a possible design, I can't help but feel that the two should be handled by separate classes. This is the design I would adopt:
classdef DataProvider < handle %your original outerclass.
properties
data;
filtermanager;
end
methods
function this = DataProvider(data, filtermanager)
this.data = data;
this.child = child;
end
function filtereddata = feedData(this)
filtereddata = this.filtermanager.filterdata(this.data);
end
end
end
classdef FilterManager < handle %container for filters. Can be implemented as singly-linked list, doubly-linked list, vector of matlab.mixin.heterogeneous, or a plain cell array
properties (SetAccess = private)
filters = {};
end
methods
function addfilter(this, filter)
assert(isa(filter, 'Filter'), 'Only object derived from Filter class can be added);
filters = [this.filters, filter];
end
%other methods to manage removals, ordering, etc. of filters
end
methods (Access = ?DataProvider)
function filtereddata = filterdata(this, data)
filtereddata = data;
for filter = this.filters
filtereddata = filter{1}.filterdata(filtereddata);
end
end
end
end
classdef Filter < abstract
methods (Abstract, Access = ?FilterManager)
function filtereddata = filterdata(data);
end
end
and an example filter:
classdef RatioFilter < Filter;
properties
ratio;
end
methods
function this = RatioFilter(ratio);
validateattributes(ratio, {'numeric'}, {'scalar'});
this.ratio = ratio;
end
end
methods (Access = ?FilterManager)
function filtereddata = filterdata(data)
filtereddata = data * this.ratio
end
end
end

2 Comments

Guillaume,
That is a huge help... my programming background is light, and my OOP background even lighter... so thank you for providing that guidance. That makes perfect sense.
I forgot to say, the advantage of decoupling the classes is that, with the above, you can at any time change which filter are applied to the data without having to tell neither the outerclass, nor the individual filters. This all handled by just one class, the FilterManager.

Sign in to comment.

More Answers (0)

Categories

Products

Tags

Community Treasure Hunt

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

Start Hunting!