问题
In Matlab class it seems to be syntactically correct to declare property that is Dependent (computed not stored) and Observable in the same time. Consider code
properties (Access = private)
instanceOfAnotherClass
end
properties (SetAccess = private, Dependent, SetObservable)
propertyTwo
end
methods
function val = get.propertyTwo(this)
val = this.instanceOfAnotherClass.propertyOne;
end
end
Does this work as expected? That is, if the property propertyOne
of an object stored in instanceOfAnotherClass
is changed is there property change event triggered by propertyTwo
? Note that propertyOne
is not Observable.
Edit:
It does not work (as I expected). 'PostSet' event is not triggered. So how do I deal with this kind of situation? Is there a better solution then to create propertyTwo
as a non Dependent and set it to the same value as 'propertyOne' every time 'propertyOne' changes?
Edit2: In reaction to Amro's edit of his answer I will explain situation more complex. Consider this 2 classes:
classdef AClass < handle
properties
a
end
end
classdef BClass < handle
properties (Access = private)
aClassInst
end
properties (Dependent, SetObservable, SetAccess = private)
b
end
methods
function this = BClass(aClass)
this.aClassInst = aClass;
end
function val = get.b(this)
val = this.aClassInst.a;
end
end
end
The class that uses all this code should not get access to AClass
. It interacts only with instance of BClass
and wants to listen to changes of property b
. however if I make property a
of AClass
observable that would not solve my problem, would it? The 'PostSet' events are not going to propagate to property b
, are they?
回答1:
It might be syntactically correct, but the listener callback will never execute. Example:
classdef MyClass < handle
properties (Access = public)
a
end
properties (SetAccess = private, Dependent, SetObservable)
b
end
methods
function val = get.b(this)
val = this.a;
end
end
end
Now try:
c = MyClass();
lh = addlistener(c, 'b', 'PostSet',@(o,e)disp(e.EventName));
c.a = 1;
disp(c.b)
As you can see the 'PostSet' callback is never executed.
EDIT
The way I see it, SetObservable
should really be set on a
not b
. Its because b
is read-only and can only change if a
changes. Now the PostSet
event would notify us that both properties have changed.
Use the same example I used above, simply move SetObservable
from b
to a
. Of course now you listen to the event as:
lh = addlistener(c, 'a', 'PostSet',@(o,e)disp(e.EventName));
EDIT#2
Sorry I didn't pay attention to the fact that you have composition (BClass has an instance of AClass as private property).
Consider this possible solution:
AClass.m
classdef AClass < handle
properties (SetObservable)
a %# observable property
end
end
BClass.m
classdef BClass < handle
properties (Access = private)
aClassInst %# instance of AClass
lh %# event listener on aClassInst.a
end
properties (Dependent, SetAccess = private)
b %# dependent property, read-only
end
events (ListenAccess = public, NotifyAccess = private)
bPostSet %# custom event raised on b PostSet
end
methods
function this = BClass(aClass)
%# store AClass instance handle
this.aClassInst = aClass;
%# listen on PostSet event for property a of AClass instance
this.lh = addlistener(this.aClassInst, 'a', ...
'PostSet', @this.aPostSet_EventHandler);
end
function val = get.b(this)
val = this.aClassInst.a;
end
end
methods (Access = private)
function aPostSet_EventHandler(this, src, evt)
%# raise bPostSet event, notifying all registered listeners
notify(this, 'bPostSet')
end
end
end
Basically we set property a
of AClass as observable.
Next inside the constructor of BClass, we register a listener for the AClass instance passed to listen on property a
changes. In the callback we notify listeners of this object that b
has changed as well
Since we can't really raise a PostSet
manually, I created a custom event bPostSet
which we raise in the previous callback function. You can always customize the event data passed, refer to the documentation to see how.
Here is a test case:
%# create the objects
a = AClass();
b = BClass(a);
%# change property a. We will not recieve any notification
disp('a.a = 1')
a.a = 1;
%# now lets listen for the 'bChanged' event on b
lh = addlistener(b, 'bPostSet',@(o,e) disp('-- changed'));
%# try to change the property a again. We shall see notification
disp('a.a = 2')
a.a = 2;
%# remove event handler
delete(lh)
%# no more notifications
disp('a.a = 3')
a.a = 3;
The output was:
a.a = 1
a.a = 2
-- changed
a.a = 3
Notice how we only interact with the BClass instance when we register our listener. Of course since all classes derive from handle
class, the instance a
and the private property aClassInst
both refer to the same object. So any changes to a.a
are immediately reflected on b.aClassInst.a
, this causes the internal aPostSet_EventHandler
to execute, which in turn notify all registered listeners to our custom event.
来源:https://stackoverflow.com/questions/11652266/dependent-observable-property-in-matlab-does-it-work