2010-12-03 40 views
0

J'essaie de rendre MATLAB un peu plus utilisable que ce qu'il est (pour moi), et l'une des choses que j'ai toujours voulu corriger est un meilleur constructeur de classe. Je veux avoir l'interface suivante:Constructeur de classe Quick-and-dirty pour MATLAB?

MyClass.new(some_args).method1; 

# instead of classical: 
obj = MyClass(some_args); 
obj.method1; 

je peux facilement y parvenir en définissant une méthode statique new:

classdef MyClass 
    methods 
    function obj = MyClass(varargin); end 
    function method1(obj,varargin); end 
    end 

    methods (Static) 
    function obj = new(varargin); obj = MyClass(varargin{:}); end 
    end 
end 

Mais cela nécessite l'ajout d'un tel procédé à toutes les classes, et il est donc pas très élégant/pratique. Je pensais que je pouvais faire le tour en définissant une classe commune avec le constructeur suivant

classdef CommonClass 
    methods (Static) 
    function obj = new(varargin) 
     # getting name of the current file (Object), i.e. basename(__FILE__) 
     try clear E; E; catch E, [s, s] = fileparts(E.stack(1).file); end; 
     # creating object with name $s 
     obj = eval([s '(varargin{:})']); 
    end 
    end 
end 

classdef MyClass < CommonClass 
end 

Cependant, cela ne fonctionne pas parce que les appels Matlab new() de Object.m, et donc j'obtenir instance de Object au lieu de MyClass.

Des idées comment je peux l'améliorer?


EDIT1:

Je voudrais que cela fonctionne aussi pour les classes créées à l'intérieur d'autres ceux:

classdef MyAnotherClass < CommonClass 
    methods 
    function obj = MyAnotherClass 
     child = MyClass.new; 
    end 
    end 
end 

>> MyAnotherClass.new 

Répondre

2

Personnellement, je ne vois pas le problème d'appeler le constructeur tel quel, mais si vous voulez l'appeler via new, le getStaticCallingClassName ci-dessous pourrait vous être utile.

est ici comment vous l'utilisez:

classdef CommonClass 
    methods (Static) 
    function obj = new(varargin) 
     %# find out which class we have to create 
     className = getStaticCallingClassName; 
     constructor = str2func(sprintf('@%s'className)); 
     %# creating object with name $s 
     obj = constructor(varargin{:}); 
    end 
    end 
end 

classdef MyClass < CommonClass 
end 

Avec cela, vous pouvez appeler

obj = MyClass.new(input,arguments); 

Et voici getStaticCallingClassName:

function className = getStaticCallingClassName 
%GETSTATICCALLINGCLASSNAME finds the classname used when invoking an (inherited) static method. 
% 
% SYNOPSIS: className = getStaticCallingClassName 
% 
% INPUT none 
% 
% OUTPUT className: name of class that was used to invoke an (inherited) static method 
% 
% EXAMPLE 
% 
% Assume you define a static method in a superclass 
%  classdef super < handle 
%  methods (Static) 
%   doSomething 
%    % do something here 
%   end 
%  end 
%  end 
% 
% Also, you define two subclasses 
%  classdef sub1 < super 
%  end 
% 
%  classdef sub2 < super 
%  end 
% 
% Both subclasses inherit the static method. However, you may be 
% interested in knowing which subclass was used when calling the static 
% method. If you call the subclass programmatically, you can easily pass 
% the name of the subclass as an input argument, but you may want to be 
% able to call the method from command line without any input and still 
% know the class name. 
% getStaticCallingClassName solves this problem. Calling it in the above 
% static method 'doSomething', it returns 'sub1' if the static method was 
% invoked as sub1.doSomething. It also works if you create an instance of 
% the subclass first, and then invoke the static method from the object 
% (e.g. sc = sub1; sc.doSomething returns 'sub1' if .doSomething calls 
% getStaticCallingClassName) 
% 
% NOTE: getStaticCallingClassName reads the last workspace command from 
%   history. This is an undocumented feature. Thus, 
%   getStaticCallingClassName may not work in future releases. 
% 
% created with MATLAB ver.: 7.9.0.3470 (R2009b) on Mac OS X Version: 10.5.7 Build: 9J61 
% 
% created by: Jonas Dorn 
% DATE: 16-Jun-2009 
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 

% get the last entry of the command line from the command history 
javaHistory=com.mathworks.mlservices.MLCommandHistoryServices.getSessionHistory; 
lastCommand = javaHistory(end).toCharArray';%'# SO formatting 
% find string before the last dot. 
tmp = regexp(lastCommand,'(?:=|\.)?(\w+)\.\w+\(?(?:.*)[;,]*\s*$','tokens'); 
try 
    className = tmp{1}{1}; 
catch me 
    className = []; 
end 
% if you assign an object, and then call the static method from the 
% instance, the above regexp returns the variable name. We can get the 
% className through getting the class of xx.empty. 
if ~isempty(className) 
    className = evalin('base',sprintf('class(%s.empty);',className)); 
end 
+0

Votre méthode est intéressante, mais elle ne tient pas compte du fait que les classes peuvent être créées via 'new' dans d'autres classes :) Ce n'est pas le style MATLAB, je sais. Je voulais juste avoir un avant-goût de Ruby dans mes m-scripts. –

+0

@Andrei Fokau: Si vous appelez 'CommonClass.new', alors vous devez passer' 'MyClass'' comme argument pour que MATLAB sache que vous voulez créer un objet de classe' MyClass'. Cependant, si vous exécutez 'MyClass.new', qui appelle la méthode statique' new' de la superclasse, alors 'getStaticCallingClassName' est exactement ce dont vous avez besoin. Voir ma modification. – Jonas

+0

Si j'essaie d'exécuter 'MyAnotherClass.new' qui appelle' MyClass.new' dans son constructeur (voir ma question mise à jour), alors j'obtiens une boucle infinie. Y a-t-il une solution pour cela? –

0

je ne pouvais manquer quelque chose, mais quel est le problème avec

method1(MyClass(some_args)) 

? (J'utilise ce modèle tout le temps).