In MATLAB, is it possible to check if an object al

2019-08-09 09:36发布

问题:

I'm trying to figure out how to ask the user whether they want to replace the previous object of the same class with the default object, or simply use the previous object, when calling the constructor.

I'm looking for actions in both these cases:

>>obj = Obj()
'obj' already exists. Replace it with default? (y/n): y
%clear obj and call default constructor to create new obj

>>obj = Obj()
'obj' already exists. Replace it with default? (y/n): n
%cancel call of Obj()

How would I do this? I've messed around with the default constructor, to no avail.

EDIT: If it makes any difference, Obj is a subclass of Handle.

回答1:

The following solution stems from several workarounds/hacks and is not part of the standard MATLAB's OO constructs. Use with caution.

You need to:

  1. evalin() into the 'caller' workspace the names and classes of the 'base' workpsace variables
  2. retrieve the last executed command
  3. extract the name of the assigned variable with e.g. regexp()
  4. compare names and classes. If a total match occurs, i.e. the variable in the 'base' workspace is being overwritten with a new instance of the same class, ask the user for input(). If the user chooses to preserve the existing object, overwrite the new instance with the existing one through evalin('caller',...).

The class foo:

classdef foo < handle
    properties
        check = true;
    end
    methods
        function obj = foo()
            % variable names and sizes from base workspace
            ws = evalin('base','whos');

            % Last executed command from window
            fid = fopen([prefdir,'\history.m'],'rt');
            while ~feof(fid)
                lastline = fgetl(fid);
            end
            fclose(fid);

            % Compare names and classes
            outname = regexp(lastline,'\<[a-zA-Z]\w*(?=.*?=)','match','once');
            if isempty(outname);  outname = 'ans'; end

            % Check if variables in the workspace have same name
            idx = strcmp({ws.name}, outname);
            % Ask questions
            if any(idx) && strcmp(ws(idx).class, 'foo')
                s = input(sprintf(['''%s'' already exists. '...
                     'Replace it with default? (y/n): '],outname),'s');
                % Overwrite new instance with existing one to preserve it
                if strcmpi(s,'n')
                    obj = evalin('caller',outname);
                end
            end
        end
    end
end

Class in action:

% create class and change a property from default (true) to false
clear b

b = foo
b = 
  foo with properties:
    check: 1

b.check = false
b = 
  foo with properties:
    check: 0

% Avoid overwriting
b = foo
'b' already exists. Replace it with default? (y/n): n

b
b = 
  foo with properties:
    check: 0

The weaknesses (see points above):

  1. applies only to cmw line and script executed commands, not functions (see link to extend to function calls). Also, might break in case of problems reading history.m.
  2. the current regex fails on a==b.
  3. Dangerous because the evalin() on user input leaves potential security threats open. Even if the input is filtered with the regexp and the string comparison, the construct might pose a problem if the code is revisited later on.


回答2:

Singleton

try this, not sure if you are familiar with it, but this mean, you only have one global instance of this specific object.



回答3:

You could use the function isobject() (see doc here) to check if the variable is an object. If true, you could then check the class of the object with class() (see doc here) and compare it to the class of the object you want to build. Something like (just to give you an idea):

if isobject(obj)
    if class(obj) == myclass
        % ask to replace it or not
    else
        % create new one over the object of a different class
    end
else
    % create new one
end

If I understand your question correctly, you probably want to put this as a constructor function for your class. I think you will have to pass the variable name when calling the constructor: obj = Obj(obj).