【问题标题】:Construct object array with no input arguments构造没有输入参数的对象数组
【发布时间】:2016-08-02 14:52:40
【问题描述】:

背景

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

期望的行为

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

  1. 如果我不传递任何参数,我将被带到一个文件选择屏幕来选择文件,并且将创建一个对象数组,我选择的每个文件都有一个元素。

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

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

目前的尝试

我已经定义了一个超类file 来处理所有文件共有的行为。这包括分配诸如filenameextension 之类的属性。我的其他类都是file的子类。

file 的构造函数中,我有两个输入参数。我的想法是,在相关的子类构造函数中,我将调用 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生成对象数组。

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. 调用超类构造函数并

  2. 不使用任何输入参数?

我愿意接受其他解决方案,这些解决方案可以帮助我解决为每种文件类型创建类的问题。

解决方案

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

子类构造函数将是:

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

在超类中:

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

【问题讨论】:

  • 那么当您不提供任何输入时,您希望系统提示您选择文件吗?
  • @Suever 是的,当我不提供任何输入时,我想被提示选择文件(默认从工作目录中),然后将创建对象数组,每个元素对应于我选择的文件。

标签: arrays matlab object constructor superclass


【解决方案1】:

执行此操作的方法是递归调用类的构造函数以生成 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

如果您想在基类中实现这一点,您可以将递归调用更改为以下内容,这将从file 超类中调用正确的子类构造函数

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

【讨论】:

  • 感谢您的回答!这解决了textfile 类的问题。唯一不好的是,这意味着我必须在给定文件类型的每个类中编写这段代码,这就是为什么我认为有一个file 超类来处理所有这些是个好主意.当我想使用file 超类构造函数来处理文件选择时,有没有办法使用你的方法?
  • @spaggy 我添加了一个示例,说明如何从超类中执行此操作
  • 这个问题是我只想调用一次超类构造函数,但是在子类中调用超类构造函数不能在条件块内完成。这意味着每次超类构造函数调用子类(filelist 中的每个文件一次,根据cellfun),超类构造函数也将被调用......
  • @Jens 为什么只调用一次超类构造函数?
  • 我写它的方式意味着文件选择发生在超类中。我在那里有一个静态方法,可以输出文件名的单元格数组。我这样做是为了在文件选择方面不必为所有子类重复代码。不过,我对其他解决方案持开放态度,如果这不能满足在创建对象数组时使用空 if nargin == 0 块的要求。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 2019-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多