Oto moja propozycja: tworzenie metodę w nadklasy nazwie add_dyn_prop
. Tę metodę należy wywoływać w podklasach, zamiast tworzyć zwykły sposób tworzenia dependent property.
Pomysł polega na tym, że nadklasa dziedziczy po dynamicprops
i korzysta z nowej właściwości z addprop
do add i ręcznie ustawia metody dostępu na podstawie swojej nazwy.
classdef klass < dynamicprops
methods (Access = protected)
function add_dyn_prop(obj, prop, init_val, isReadOnly)
% input arguments
narginchk(2,4);
if nargin < 3, init_val = []; end
if nargin < 4, isReadOnly = true; end
% create dynamic property
p = addprop(obj, prop);
% set initial value if present
obj.(prop) = init_val;
% define property accessor methods
% NOTE: this has to be a simple function_handle (@fun), not
% an anonymous function (@()..) to avoid infinite recursion
p.GetMethod = @get_method;
p.SetMethod = @set_method;
% nested getter/setter functions with closure
function set_method(obj, val)
if isReadOnly
ME = MException('MATLAB:class:SetProhibited', sprintf(...
'You cannot set the read-only property ''%s'' of %s', ...
prop, class(obj)));
throwAsCaller(ME);
end
obj.(prop) = val;
end
function val = get_method(obj)
val = obj.(prop);
end
end
end
end
teraz w podklasie, zamiast definiowania właściwość zależna zwykły sposób, możemy skorzystać z tej nowej funkcji dziedziczonej w konstruktorze zdefiniować właściwość dynamiczna:
classdef subklass < klass
%properties (Dependent, SetAccess = private)
% name
%end
%methods
% function val = get.name(obj)
% val = 'Amro';
% end
%end
methods
function obj = subklass()
% call superclass constructor
obj = [email protected]();
% define new properties
add_dyn_prop(obj, 'name', 'Amro');
add_dyn_prop(obj, 'age', [], false)
end
end
end
Wyjście:
>> o = subklass
o =
subklass with properties:
age: []
name: 'Amro'
>> o.age = 10
o =
subklass with properties:
age: 10
name: 'Amro'
>> o.name = 'xxx'
You cannot set the read-only property 'name' of subklass.
Oczywiście można teraz dostosować metodę gettera na podstawie nazwy właściwości zgodnie z pierwotnym zamierzeniem.
EDIT:
Na podstawie uwag, proszę znaleźć poniżej lekkim odmianie tej samej techniki omówione powyżej.
Chodzi o to, aby podklasa wymagała utworzenia właściwości (zdefiniowanej jako abstrakcyjna w superklasie) zawierającej nazwy pożądanych właściwości dynamicznych, które mają zostać utworzone. Konstruktor superklasy tworzyłby wówczas określone właściwości dynamiczne, ustawiając ich metody dostępu na ogólne funkcje (które mogłyby dostosować swoje zachowanie w oparciu o nazwę właściwości, zgodnie z żądaniem). Korzystam z tej samej funkcji, o której wspomniałem wcześniej.
W podklasie po prostu musimy zaimplementować odziedziczoną właściwość abstrakcyjną dynamic_props
, zainicjowaną listą nazw (lub {}
, jeśli nie chcesz tworzyć żadnej właściwości dynamicznej). Na przykład możemy napisać:
classdef subklass < klass
properties (Access = protected)
dynamic_props = {'name', 'age'}
end
methods
function obj = subklass()
obj = [email protected]();
end
end
end
nadklasą jest podobny do tego, co mieliśmy wcześniej wcześniej, tylko teraz jest to jego obowiązkiem jest wywołać add_dyn_prop
w jego konstruktora dla każdej z nazw właściwości:
classdef klass < dynamicprops % ConstructOnLoad
properties (Abstract, Access = protected)
dynamic_props
end
methods
function obj = klass()
assert(iscellstr(obj.dynamic_props), ...
'"dynamic_props" must be a cell array of strings.');
for i=1:numel(obj.dynamic_props)
obj.add_dyn_prop(obj.dynamic_props{i}, [], false);
end
end
end
methods (Access = private)
function add_dyn_prop(obj, prop, init_val, isReadOnly)
% input arguments
narginchk(2,4);
if nargin < 3, init_val = []; end
if nargin < 4, isReadOnly = true; end
% create dynamic property
p = addprop(obj, prop);
%p.Transient = true;
% set initial value if present
obj.(prop) = init_val;
% define property accessor methods
p.GetMethod = @get_method;
p.SetMethod = @set_method;
% nested getter/setter functions with closure
function set_method(obj,val)
if isReadOnly
ME = MException('MATLAB:class:SetProhibited', sprintf(...
'You cannot set the read-only property ''%s'' of %s', ...
prop, class(obj)));
throwAsCaller(ME);
end
obj.(prop) = val;
end
function val = get_method(obj)
val = obj.(prop);
end
end
end
end
Uwaga: Nie użyłem atrybutu klasy ConstructOnLoad
lub atrybutu właściwości Transient
, ponieważ nadal nie jestem pewien, w jaki sposób wpłynęłoby to na ładowanie obiektu z zapisanego pliku MAT w odniesieniu do właściwości dynamicznych.
>> o = subklass
o =
subklass with properties:
age: []
name: []
>> o.name = 'Amro'; o.age = 99
o =
subklass with properties:
age: 99
name: 'Amro'
To jest najbliżej tego, co zrobiłem: każda z podklas definiuje właściwość 'dynamic_props', a nadklasa (wymuszona na' [ConstructOnLoad] (http://www.mathworks.com/help/matlab/matlab_oop/class -constructor-methods.html) ') inicjuje je wszystkie w swoim konstruktorze, ustawiając GetMethod na anonimową funkcję, która przechowuje nazwę właściwości, aby umożliwić ogólną implementację. Myślę, że jest nieco prostszy i lepiej zdefiniowany dla użytkownika. Chciałbym, żeby Matlab miał bardziej dynamiczne możliwości programowania OO. Twoje zdrowie! –
@MattB .: Wysłałem alternatywną implementację na podstawie tego, co opisałeś. – Amro
Tak, dokładnie jak to zrobiłem, z wyjątkiem Transient = true i constructOnLoad. Wydaje się, że działa dobrze z zapisywaniem i ładowaniem dla moich celów. Zastanawiałem się, czy nie odpowiedzieć na moje własne pytanie, ale uznałem, że jest wystarczająco blisko. Teraz jest naprawdę! –