构造没有输入参数的对象数组

Construct object array with no input arguments

背景

我从不同类型的文件中提取和存储数据,例如 .csv 和数据库文件。它们通常是大文件,我已经有适当的方法从中提取数据。

期望的行为

我们以class textfile为例。我希望能够创建一个 textfile 对象数组,其中每个元素对应一个唯一的文本文件。我希望能够用一个参数调用 textfile,或者 根本没有参数

  1. 如果我不传递任何参数,我将被带到文件 select 屏幕到 select 文件,并且将创建一个对象数组,一个元素用于每个文件我 selected.

  2. 如果传递了一个参数,我希望根据该参数创建数组。如果是目录路径,请再次打开文件 select 屏幕。如果它是文件路径的元胞数组,则创建这些文件的对象数组。

我希望能够轻松创建更多 class 具有相同基本行为的 textfile

到目前为止的尝试

我定义了一个 superclass file 来处理所有文件共有的行为。这包括分配 filenameextension 等属性。我的其他 class 都是 file.

的子class

file 的构造函数中,我有两个输入参数。我的想法是,在相关的 subclass 构造函数中,我会调用 file 构造函数。第一个输入参数是文件类型,例如txt,而第二个是我在创建 textfile 数组时选择的参数。为简单起见,假设我希望能够处理的唯一类型 arg 是从中选择文件的目录路径。

classdef textfile < file
    methods
        function textfileObject = textfile(arg)
            if nargin == 0
                arg = '';
            end
            textfileObject@file('txt',arg);
    end
end

file构造函数,根据我创建textfile对象时arg是什么,按照using the No Input Argument Constructor Requirement.[=36=生成对象数组]

classdef file < handle
    properties
        Path
    end
    methods
        function FileObject = file(FileType,arg)
            if nargin == 2
                FileList = file.SelectFiles(FileType,arg);
                FileObject(numel(FileList),1) = file;
                for filecount = 1:numel(FileObject)
                    FileObject(filecount,1).Path = FileList{filecount};
                end
            end
        end
    end
    methods(Static)
        function FileList = SelectFiles(DirectoryPath)
             % Some selection dialogs. Returns a cell array of filepaths
        end
    end
end

这在 arg 是一个目录时有效,因为当对象数组在 textfile 中初始化且没有输入参数时,arg 设置为 '' 这有效与其余的构造函数。

但是,我希望在创建 textfile 对象时能够没有任何输入参数,但这不适用于构造函数的无输入参数规则。

问题

有没有办法在

时创建对象数组
  1. 调用超级class构造函数和

  2. 没有使用任何输入参数?

我对其他解决方案持开放态度,这些解决方案可以帮助我解决为每种文件类型创建 classes 的问题。

解决方案

事实证明,您可以使用匿名函数从 superclass 调用 subclass 构造函数。实际上,您可以调用没有输入参数的 subclass 构造函数,然后在使用这些文件名作为输入再次(递归)调用 subclass 之前在 superclass 中生成文件名.谢谢@Suever。

subclass 构造函数将只是:

classdef textfile < file
    methods
        function textfileObject = textfile(varargin)
            textfileObject@file('txt',varargin{:});
        end
    end
end

而在超class:

classdef file < handle
    properties
        Path
    end
    methods
        function FileObject = file(FileType,varargin)

            % Subclass constructor handle
            Constructor = @(FilePath)feval(class(FileObject),FilePath);

            % No subclass arguments
            if nargin == 1
                FileList = file.SelectFiles(FileType,'');
                for a = 1:numel(FileList)
                    FileObject(a,1) = Constructor(FileList{a});
                end

            % One subclass argument
            elseif nargin == 2
                arg = varargin{1};
                if ischar(arg)
                    FileStruct = dir(arg);
                    if numel(FileStruct) == 1
                        FileObject.Path = arg;
                    end
                end

            % Too many subclass arguments
            else
                error('Subclasses of file only take one or no input arguments');
            end
        end
    end
end

执行此操作的方法是递归调用 class 的构造函数以生成 textfile 对象的数组。

classdef textfile < file

    methods
        function self = textfile(arg)
            if ~exist('arg', 'var')
                % Get list of files somehow
                [fnames, pname] = uigetfile('MultiSelect', 'on');
                filelist = fullfile(pname, fnames);

                % Call the constructor again for each file
                output = cellfun(@textfile, filelist, 'uniformoutput', 0);

                % Flatten the cell array of objects into an array of the right shape
                self = reshape([output{:}], size(filelist));
            else
                % Do default construction here
                self = self@file('txt', arg);
            end
        end
    end
end

如果你想在基础 class 中实现它,你可以将递归调用更改为如下所示,它会从 [=13] 中调用正确的 subclass 构造函数=]超级class

constructor = @(varargin)feval(class(self), varargin{:});
output = cellfun(constructor, filelist, 'uniformoutput', 0);