A hypothetical scenario to ask my question:
Let's say we have 2 entities: a boss and an employee. When an employee completes a job, he/she wants to let people know. In this case, the boss 'kind of' subscribes to the message and decides what to do
I implemented this interface which has an abstract method that any other class can implemented. In this (cause he/she will decide what he/she wants to do):
classdef (Abstract) Interface < handle
methods
getJobsCompleted(n)
end
end
The boss class inherits Interface and implements the method getJobsCompleted()
classdef Boss < Interface & handle
properties
myEmployee
end
methods
function this = Boss()
this.myEmployee = Employee(this)
this.myEmployee.doJobs();
end
%My boss implements (i.e. decides what to do) the abstract method
function getJobsCompleted(n)
%DO SOMETHING with n
end
end
end
And, finally, the employee performs the jobs and notifies the boss.
classdef Employee < handle
properties
numJobsCompleted;
boss = [];%pointer or reference to Boss instance
end
methods
function this = Employee(myBoss)
this.boss = myBoss; %reference/pointer to my boss so I know who to notify
end
function doJobs()
%% do something then let boss know
this.numJobsCompleted = 40;
this.boss.getJobsCompleted(this.numJobsCompleted);
end
end
end
What I have been attempting to unsuccessfully do is to pass a reference to the Employee class so that he/she knows which boss to notify.
i.e.
in Boss
this.myEmployee = Employee(this)
This will work, you just need to explicitly accept the object instance as an input argument to all methods. You'll need to update the following two function definitions:
function doJobs(this)
function getJobsCompleted(this, n)
That being said, a better way of doing this may be to use events and listeners. You would then have the employee emit a "JobCompleted" event and have the boss listen to those events for all of their employees. This prevents the employee from needing to keep track of their boss.
classdef Boss < handle
properties
Employees
Listeners
end
methods
function this = Boss(employees)
this.Employees = employees;
this.Listeners = addlistener(employees, 'JobCompleted', #this.onJobCompleted);
end
function onJobCompleted(this, employee, evnt)
fprintf('%s completed a job!\n', employee.Name);
end
end
end
Employee.m
classdef Employee < handle
properties
Name
CompletedJobs = 0
end
events
JobCompleted
end
methods
function this = Employee(name)
this.Name = name;
end
function doJob(this)
this.CompletedJobs = this.CompletedJobs + 1;
notify(this, 'JobCompleted')
end
end
end
And use it like:
employees(1) = Employee('Fred');
employees(2) = Employee('Bill');
boss = Boss(employees);
doJob(employees);
doJob(employees(1));
Related
In this article (https://blogs.mathworks.com/loren/2012/07/16/who-what-why-but-not-this/) near the bottom Loren says that class properties can be the same as keywords. However, how is this possible? If you write a classdef script any attempt to use a keyword (including class keywords like "events") in the properties block gets a red syntax error. Was she mistaken? I'm asking because I really want a property name to be a keyword for a particular application.
Its possible by the use of dynamic properties, for example:
classdef test < dynamicprops
methods
function obj = test()
end
end
end
var = test();
var.addprop ( 'events' );
var.events = 123;
It can make code harder to maintain and its a bit overkill if you only want to name a single property the same as a keyword, in that instance why dont you do something like capitilizing the var name, or prepending it with something - so it still reads like what you want but it doesn't cause the name clash:
classdef test
properties
Events
myIf
% etc...
end
methods
function obj = test()
end
end
end
The property postSet of MATLAB handle classes are very handy, however I would be happy to be able to trigger nested classes separately. A minimal example with two nested classes for illustration:
classdef parentClass < handle
properties (SetObservable = true)
childClass
end
methods
function this = parentClass()
this.childClass = childClass();
end
end
end
and
classdef childClass < handle
properties (SetObservable = true)
value
end
methods
function this = childClass()
this.value = 0;
end
end
end
In the example script "runTest"
p = parentClass();
addlistener(p.childClass,'value','PostSet',#(o,e)disp('child value set'));
addlistener(p,'childClass','PostSet',#(o,e)disp('parent value set'));
p.childClass.value = 1;
The result is (as expected)
>> runTest
child value set
However, I am looking for an elegant way to detect the property change on both levels such that the result would be:
>> runTest
child value set
parent value set
One way to do this is to use the fact that the PostSet event gets triggered by default even when the previous and current values are the same. In the constructor of parentClass, we add a listener to the childClass's PostSet event, and the event handler only reassigns the childClass object:
classdef parentClass < handle
properties (SetObservable = true)
childClass
end
methods
function this = parentClass()
this.childClass = childClass();
addlistener(this.childClass,'value','PostSet', #this.handlePropEvent);
end
function handlePropEvent(this, src, event)
this.childClass = this.childClass;
end
end
end
Note that you would want to be more careful implementing this so that the event listener gets adequately disposed of (and reassigned) if the childClass property is assigned a different object.
In practice, childClass should probably implement its own event type which gets triggered by all property changes you're interested in, and parentClass only listens to that event.
I'm trying to change a property in a class called houses via a utility method which is Static. I'm getting terribly confused with the reference obj as I don't know when and where it should be used. I am trying to bypass the constructor method so I can access the setProperty method, but I am getting errors such as too many output arguments. I've tried passing in obj as well as x, but I get similar errors. However, I can change the property a if I pass in a value to the constructor method.
classdef houses
properties
a;
end
methods
% constructor method
function obj = houses()
end
end
methods (Static)
function setProperty(x)
obj.a = x;
end
end
end
In general, you should not use static methods to set properties of a class. If your property is public, then you can use a static method but it is highly recommended that you do not. If your property is private/protected, then you definitely cannot use a static method to modify it.
Your class should look like this then (I took the liberty of stating explicitly the access properties of each block):
classdef houses
properties (Access = private)
a;
end
methods (Access = public)
% constructor method
function obj = houses()
end
function SetA(obj, a)
obj.a = a;
end
function DoSomething(obj, more_parameters)
% Lengthy stuff here
end
end
end
Now, regarding your question about obj: the answer is you must pass obj as the first argument of every instance method. The variable obj refers to the current instance of the class in a generic way. See for example the method DoSomething.
Static methods do not have access to any of the properties of the class, unless public. As such, when declaring a static method, you should not pass the obj variable.
Last thing: always use explicit access modifiers for your properties and methods. It will save you some headaches.
A static method is not typically supposed to access an object (hence it does not have access to obj).
If you want to modify a static propperty (shared by all objects, and the class itself), you can use something like:
classdef houses
properties (Static)
a;
end
methods
% constructor method
function obj = houses()
end
end
methods (Static)
function setProperty(x)
houses.a = x;
end
end
end
Regarding obj, it is the 1st argument of every methods (non static). So when you do:
o = myClass();
o.myMethod(args);
Matlab will see this as:
myMethod(o, args);
So when you define the method, you have to put obj as the 1st argument (in fact you can choose any name, it does not have to be obj).
I implemented a class in Matlab which derives from matlab.mixin.Copyable. I want to suppress the output of the command window so that the user does not has information about the class. I want to do this for security reasons. For example:
a = myStack;
a
ans=
myStack with no properties.
But the user can click myStack and it gives information about the class. I know that I can overload display for this, but the behavior that I want is like follows:
b = handle(1);
b
ans=
handle
How I can do this?
Thanks.
You have to derive from matlab.mixin.CustomDisplay interface and override the getPropertyGroups method.
For the specific purpose of removing the link to help in the header, also override getHeader method.
NB: I don't see how you can truly handle security in this way. Users will still have other means to get details about your class. For instance meta = ?MyClass, or just edit MyClass if not encrypted with pcode, or simply in the editor just typing myInstance. and let intellisense list all non hidden/private methods and properties.
Example for the display you want to have:
classdef foo < matlab.mixin.CustomDisplay
properties
Login = 'root';
Password = '1234'
end
methods (Access = protected)
function [str] = getHeader(obj)
str = mfilename;
end
function [pg] = getPropertyGroups(obj)
pg = [];
end
function [str] = getFooter(obj)
str = sprintf('\n');
end
end
end
May be better solution to avoid displaying some properties (including from help-link):
classdef foo < matlab.mixin.CustomDisplay
properties (SetAccess = private, GetAccess = private) % here remove any public access, use '(Hidden)' if only want to remove from display and help
Login = 'root';
Password = '1234'
end
end
NB: Careful, as #Daniel wrote, whatever you will do, struct(a) reveals all property names and values.
As well as the method from #CitizenInsane, you may get what you want by simply adding the Hidden = true attribute to some or all of your properties.
Reiterating what others have said, though, if you're doing this in order to seriously prevent people from understanding the internals of your class, struct(a) will always show them the properties. You can overload your class with a struct method that errors out, but then builtin('struct', a) would still do the original thing. Also ?Classname will provide meta-information about the class that includes its properties.
Using Matlab R2012a, I have the following class hierarchy:
classdef Parent < handle
properties (Abstract, SetAccess = protected)
Limit
end
end
classdef SimpleChild < Parent
properties (SetAccess = protected)
Limit = 1.0
end
end
classdef ExtendedChild < Parent
properties (Access = private)
Child = SimpleChild
end
properties (Dependent, SetAccess = protected)
Limit
end
methods
function this = ExtendedChild
this.Limit = 2;
end
function output = get.Limit(this)
output = this.Child.Limit;
end
function set.Limit(this,input)
this.Child.Limit = input;
end
end
end
This a simple example where the "Parent" class defines an abstract "Limit" property, which is implemented in both the "SimpleChild" and the "ExtendedChild" class. The "ExtendedChild" class encapsulates a private instance on the "SimpleChild" class and forward the access methods (get/set) to the private instance. Constructing an "ExtendedChild" instance fails with the following message:
>> obj = ExtendedChild
Setting the 'Limit' property of the 'SimpleChild' class is not allowed.
Error in ExtendedChild/set.Limit (line 16)
this.Child.Limit = input;
Error in ExtendedChild (line 10)
this.Limit = 2;
I would have expected the "Limit" property to be settable since it is defined in the "Parent" class with a protected SetAccess. I can make the problem disappear if the property is implemented directly in the "Parent" class, but then I cannot redefine it as dependent in the "ExtendedChild" class, which is the point of the construction (separation of interface and implementation).
Can someone tell me if I'm doing something wrong?
Since the Limit property of SimpleChild is protected, you can only set its value from SimpleChild or a subclass of SimpleChild, which is not the case for ExtendedChild.
I'm not entirely sure what you're trying to achieve, so can't really advise on what the "best" way to do it might be. But I would guess that whatever you want, it's unlikely that having a set method for a Dependent property is the right way to achieve it - there are only very rare reasons why you might want to do that.