MATLAB Answers

set class property only once

13 views (last 30 days)
Marc Youcef
Marc Youcef on 12 Mar 2020
Answered: per isakson on 21 Mar 2020
I am having multiples classes which needs to read a shared common variable called 'MasterData'.
This MasterData variable is getting its data from an api call. In order to avoid to make this api call in each of my different classes that need it, I wanted to define MasterData as a propery in a handle class (MasterDataConfiguration class) and then make other classes inherit from that superclass.
classdef MasterDataConfiguration < handle
properties
MasterData
end
methods
function obj = MasterDataConfiguration2(~)
% Get MasterData from CyPET4
% Read data form config
ini = IniConfig();
ini.ReadFile('MPS_AutoJSON_ConfigFile.ini');
% API info
APIbaseurl = ini.GetValues('Web App API', 'PreformFilesrequestURI_Prod');
APIparameter = 'admin/masterdata';
% API call
options = weboptions('Timeout',120);
obj.MasterData = webread([APIbaseurl,APIparameter],options);
disp('MasterData API was queried');
end
For the sub clases which would inherit from the above class:
classdef SubClassExample < MasterDataConfiguration
properties
ColdHalfDataStruct
end
methods
function obj = SubClassExample(OtherObj)
%ColdHalfData Construct an instance of ColdHalfData from a PreformDataObj of
%class PreformData
% work done on MasterData
obj.MasterData
end
end
end
My difficulty here is that I get the API requested each time I create a subclass object SubClassExample.
What I would like is that the attribute MasterData from class MasterDataConfiguration gets set once and for all and the other subclasses simply refers to it without re generating it.
I tried using Properties (constant) but I can't make an API call in such way.
I read some documentation here :
But could not understand whet is meant by the following :
"MATLAB® evaluates property default values only once when loading the class. MATLAB does not reevaluate the assignment each time you create an object of that class. If you assign an object as a default property value in the class definition, MATLAB calls the constructor for that object only once when loading the class."
In my case I see the API is always called.
Thanks in advance for any hint on how to proceed.

  0 Comments

Sign in to comment.

Accepted Answer

Guillaume
Guillaume on 12 Mar 2020
Edited: Guillaume on 12 Mar 2020
It sounds like you want a singleton property. This is how I'd designed it. As commented in Steven's answer, this doesn't and should not involve inheritence:
classdef MasterConfiguration < handle %handle require so it can modify its own properties
properties (SetAccess = private)
MasterData
end
methods
function this = MasterConfiguration() %constructor
this.Initialise(); %Initialise
end
function Initialise(this) %Actual initialisation code. Decoupled from the constructor, so it can be reinitialised as needed
%... initialisation code
end
end
end
classdef MasterDataUser %can be handle or value class depending on needs
properties (Constant)
MasterDataConfiguration = MasterConfiguration; %singleton object shared by all instances
end
methods
%...
function ReinitialiseMasterData(this) %in case MasterData need to be reread
this.MasterDataConfiguration.Initialise(); %all instances of MasterDataUser will see the newly initialised MasterConfiguration
end
end
end
If several classes need access to the same shared MasterData, then they must derive from MasterDataUser not from MasterConfiguration.

  3 Comments

Marc Youcef
Marc Youcef on 12 Mar 2020
It now gets much more clear. For other classes that would use same shared MasterData, could I do same implementation for them as for class MasterDataUser ? I want to avoid those other classes from inheriting from MasterDataUser because they are really different classes and have different properties except their common need to use MasterData.
Guillaume
Guillaume on 12 Mar 2020
No, they will all have to inherit from this class holding the singleton. Call it MasterDataInterface if you wish.
The only other option is to do the sharing with a global variable with all the pitfalls that entails.
Marc Youcef
Marc Youcef on 13 Mar 2020
That is perfectly doing the job. Thanks to you both for detailed guidance.

Sign in to comment.

More Answers (2)

Steven Lord
Steven Lord on 12 Mar 2020
It sounds like you want an immutable property as described here or perhaps to have your classes that want to use the data to store a MasterDataConfiguration handle object in their properties. In that latter case, you may want to assign the MasterDataConfiguration handle object in the property definition for the objects that need it rather than in their constructors. See the "Expression Evaluation in Handle and Value Classes" section on this documentation page for more information about why that may be more appropriate for your class hierarchy.

  3 Comments

Marc Youcef
Marc Youcef on 12 Mar 2020
Thanks for the support.
I probably misunderstood your suggesion as it did not work as expected for me.
This is what I did :
classdef MasterDataConfiguration < handle
properties
MasterData2
end
methods
function obj = MasterDataConfiguration2(~)
% Get MasterData
% Read data form config
ini = IniConfig();
ini.ReadFile('MPS_AutoJSON_ConfigFile.ini');
% API info
APIbaseurl = ini.GetValues('Web App API', 'PreformFilesrequestURI_Prod');
APIparameter = 'admin/masterdata';
% API call
options = weboptions('Timeout',120);
obj.MasterData = webread([APIbaseurl,APIparameter],options);
disp('MasterData API was queried');
end
And for the sub class:
classdef SubClassExample < MasterDataConfiguration
properties (Constant)
MasterData = MasterDataConfiguration
end
properties
ColdHalfDataStruct
end
methods
function obj = SubClassExample(OtherObj)
%ColdHalfData Construct an instance of ColdHalfData from a PreformDataObj of
%class PreformData
% work done on MasterData
obj.MasterData
end
end
end
Each time I construct SubClassExample, I get the API being called while I would like it to be called once and just refer to MasterData only.
Can you give more details on you solution with classes?
I also tried the following and still API was called each time (which is logic as it is in the constructor but I do not see how to do that in properties):
classdef MasterDataConfiguration2 < handle
properties (SetAccess = immutable)
% MasterData = load("MasterData.mat");
MasterData
end
methods
function obj = MasterDataConfiguration2(~)
% Read data form config
ini = IniConfig();
ini.ReadFile('MPS_AutoJSON_ConfigFile.ini');
% API info
APIbaseurl = ini.GetValues('Web App API', 'PreformFilesrequestURI_Prod');
APIparameter = 'admin/masterdata';
% API call
options = weboptions('Timeout',120,'Debug',true);
obj.MasterData = webread([APIbaseurl,APIparameter],options);
end
end
end
Guillaume
Guillaume on 12 Mar 2020
I'm very confused about your design. If MasterData in subClassExample is a property of type MasterDataConfiguration, why does subClassExample derive from MasterDataConfiguration? It sounds like there should be no inheritance from MasterDataConfiguration.
I'm a bit unclear on the desired lifetime for MasterData. What the bit about constant properties say, is that if the property is constant, the initialisation function is called only once, when the class is loaded which is typically the firsts time an object is created (documentation is purposefully unclear, this may depends on the jit optimisation). It is then never called again, regardless of the number of instances of the class. The only way to get it to be called again would be to restart matlab, use clear classes or possibly edit the class code.
Marc Youcef
Marc Youcef on 12 Mar 2020
Indeed I should have removed that inheritance. I can't try it out now. Will do that tomorrow.
Your description is exactly what I would be looking for. Meaning that I would like subClassExample first instance to create only once the MasterData property. In return, to build MasterData property, it will construct MasterDataConfiguration.
Then when another instance of subClassExample is generated, I am hoping that it would not construct again MasterDataConfiguration. Removing the inheritance should solve that.
I try out and let you know.
Thanks.

Sign in to comment.


per isakson
per isakson on 21 Mar 2020
Here is an minimal working example of the design, which I think OP tried to implement. That is, use the fact that "MATLAB® evaluates property default values only once when loading the class.".
"I tried using Properties (constant) but I can't make an API call in such way." The trick is to put the code, which creates the value of MaterData, in a static method (or an ordinary function) and call that in the property block.
First, I create three instancies of SubClassExample(). The method, configureMasterData(), is called only for the first instance. (Instead of calling the API, I call randi() to create a vector of three random whole numbers.) Next, I show that the values of the property, MasterData, is identical for the three instances.
>> sce_1 = SubClassExample();
MasterData API was queried
>> sce_2 = SubClassExample();
>> sce_3 = SubClassExample();
>> sce_1.MasterData
ans =
8 9 2
>> sce_2.MasterData
ans =
8 9 2
>> sce_3.MasterData
ans =
8 9 2
where
classdef MasterDataConfiguration < handle
properties ( SetAccess = private )
MasterData = MasterDataConfiguration.configureMasterData;
end
methods ( Static, Access = private )
function master_data = configureMasterData();
master_data = randi( [1,9], 1,3 );
disp('MasterData API was queried');
end
end
end
and
classdef SubClassExample < MasterDataConfiguration
properties
ColdHalfDataStruct
end
end

  0 Comments

Sign in to comment.

Products


Release

R2019b

Community Treasure Hunt

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

Start Hunting!

Translated by