В основном, любое время, Вы хотите, чтобы некоторый другой класс был ответственен за жизненный цикл объектов Вашего класса, или у Вас есть причина предотвратить разрушение объекта, можно сделать деструктор частным.
, Например, при выполнении своего рода вещи подсчета ссылок у Вас может быть объект (или менеджер, который был "другом" редактор), ответственный за подсчет количества ссылок на себя, и удалите его, когда число поражает нуль. Частный dtor препятствовал бы тому, чтобы кто-либо еще удалил его, когда были все еще ссылки на него.
Для другого экземпляра, что, если у Вас есть объект, который имеет менеджера (или оно), который может уничтожить его или может отказаться уничтожать его в зависимости от других условий в программе, таких как соединение с базой данных, являющееся открытым или записанный файл. У Вас могли быть "request_delete" метод в классе или менеджер, который проверит, что условие и он или удалят или уменьшат и возвратят состояние, говоря Вам, что это сделало. Это намного более гибко, который "удаляет" просто вызов.
Вы можете получить некоторые функциональные возможности с классами MATLAB нового стиля:
classdef (Sealed) Colors
properties (Constant)
RED = 1;
GREEN = 2;
BLUE = 3;
end
methods (Access = private) % private so that you cant instantiate
function out = Colors
end
end
end
На самом деле это не тип, но поскольку MATLAB слабо типизирован, если вы используете целые числа, вы можете делать то, что приближает их:
line1 = Colors.RED;
...
if Colors.BLUE == line1
end
В этом случае "перечисления" MATLAB близки к перечислениям в стиле C - синтаксис замены целых чисел.
При осторожном использовании статических методов вы можете даже сделать перечисления MATLAB похожими на Ada в изощренности, но, к сожалению, с более неуклюжим синтаксисом.
Если вы хотите сделать что-то похожее на то, что предложил Марк , вы можете просто создать структуру для представления перечисленных типы вместо совершенно нового класса:
colors = struct('RED', 1, 'GREEN', 2, 'BLUE', 3);
Одно из преимуществ состоит в том, что вы можете легко получить доступ к структурам двумя разными способами. Вы можете указать поле напрямую, используя имя поля:
a = colors.RED;
или вы можете использовать имена динамических полей , если у вас есть имя поля в строке:
a = colors.('RED');
По правде говоря, это дает несколько преимуществ что предложил Марк и создал совершенно новый класс для представления объекта "перечисление":
Однако, если вам не нужны такие сложности и просто нужно что-то сделать быстро, структура вероятно, самая простая и понятная реализация. Он также будет работать со старыми версиями MATLAB, которые не используют новейшую структуру ООП.
Вы также можете использовать классы перечисления Java из вашего кода Matlab. Определите их в Java и поместите в путь javaclasspath вашего Matlab.
// Java class definition
package test;
public enum ColorEnum {
RED, GREEN, BLUE
}
Вы можете ссылаться на них по имени в M-коде.
mycolor = test.ColorEnum.RED
if mycolor == test.ColorEnum.RED
disp('got red');
else
disp('got other color');
end
% Use ordinal() to get a primitive you can use in a switch statement
switch mycolor.ordinal
case test.ColorEnum.BLUE.ordinal
disp('blue');
otherwise
disp(sprintf('other color: %s', char(mycolor.toString())))
end
Однако он не будет улавливать сравнения с другими типами. А сравнение со строкой имеет нечетный размер возврата.
>> test.ColorEnum.RED == 'GREEN'
ans =
0
>> test.ColorEnum.RED == 'RED'
ans =
1 1 1
Вы можете создать класс Matlab, который ведет себя как старый шаблон перечисления Java . Модификация решения Марка могла бы превратить его из определений типов в стиле C в более похожие на типы безопасных перечислений в стиле Java. В этой версии значения в константах являются типизированными объектами Color.
Плюсы:
Недостатки:
В целом, я не знаю, какой подход лучше. Ни то, ни другое не использовалось на практике.
classdef (Sealed) Color
%COLOR Example of Java-style typesafe enum for Matlab
properties (Constant)
RED = Color(1, 'RED');
GREEN = Color(2, 'GREEN');
BLUE = Color(3, 'BLUE');
end
properties (SetAccess=private)
% All these properties are immutable.
Code;
Name;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
methods (Access = private)
%private so that you can't instatiate directly
function out = Color(InCode, InName)
out.Code = InCode;
out.Name = InName;
end
end
methods (Static = true)
function needa(obj)
%NEEDA Asserts that obj must be a Color
if ~isa(obj, mfilename)
error('Input must be a %s; got a %s', mfilename, class(obj));
end
end
end
methods (Access = public)
function display(obj)
disp([inputname(1) ' =']);
disp(obj);
end
function disp(obj)
if isscalar(obj)
disp(sprintf('%s: %s (%d)', class(obj), obj.Name, obj.Code));
else
disp(sprintf('%s array: size %s', class(obj), mat2str(size(obj))));
end
end
function out = eq(a, b)
%EQ Basic "type-safe" eq
check_type_safety(a, b);
out = [a.Code] == [b.Code];
end
function [tf,loc] = ismember(a, b)
check_type_safety(a, b);
[tf,loc] = ismember([a.Code], [b.Code]);
end
function check_type_safety(varargin)
%CHECK_TYPE_SAFETY Check that all inputs are of this enum type
for i = 1:nargin
if ~isa(varargin{i}, mfilename)
error('Non-typesafe comparison of %s vs. %s', mfilename, class(varargin{i}));
end
end
end
end
end
Вот функция для его реализации.
function do_stuff_with_color(c)
%DO_STUFF_WITH_COLOR Demo use of the Color typesafe enum
Color.needa(c); % Make sure input was a color
if (c == Color.BLUE)
disp('color was blue');
else
disp('color was not blue');
end
% To work with switch statements, you have to explicitly pop the code out
switch c.Code
case Color.BLUE.Code
disp('blue');
otherwise
disp(sprintf('some other color: %s', c.Name));
end
Пример использования:
>> Color.RED == Color.RED
ans =
1
>> Color.RED == 1
??? Error using ==> Color>Color.check_type_safety at 55
Non-typesafe comparison of Color vs. double
Error in ==> Color>Color.eq at 44
check_type_safety(a, b);
>> do_stuff_with_color(Color.BLUE)
color was blue
blue
>> do_stuff_with_color(Color.GREEN)
color was not blue
some other color: GREEN
>> do_stuff_with_color(1+1) % oops - passing the wrong type, should error
??? Error using ==> Color>Color.needa at 26
Input must be a Color; got a double
Error in ==> do_stuff_with_color at 4
Color.needa(c); % Make sure input was a color
>>
Незначительная причуда в обоих подходах: соглашение C о размещении константы слева от символа "= = "предотвращение неправильного назначения здесь не так сильно помогает. В Matlab, если вы случайно используете "=" с этой константой в LHS вместо ошибки, он просто создаст новую локальную структурную переменную с именем Colors и замаскирует класс перечисления.
>> Colors.BLUE = 42
Colors =
BLUE: 42
>> Color.BLUE = 42
Color =
BLUE: 42
>> Color.RED
??? Reference to non-existent field 'RED'.
Если у вас есть доступ к панели инструментов статистики, вы можете рассмотреть возможность использования категориального объекта .
На самом деле в MATLAB R2009b есть ключевое слово, называемое 'enumeration' . Кажется, это недокументировано, и я не могу сказать, что знаю, как его использовать, но функциональность, вероятно, есть.
Вы можете найти его в matlabroot \ toolbox \ distcomp \ examples \ + examples
classdef(Enumeration) DmatFileMode < int32
enumeration
ReadMode(0)
ReadCompatibilityMode(1)
WriteMode(2)
end
<snip>
end
Опробовав другие предложения на этой странице, я остановился на полностью объектно-ориентированном подходе Эндрю. Очень приятно - спасибо, Андрей.
Однако, если кому-то интересно, я внес (как мне кажется) некоторые улучшения. В частности, я убрал необходимость дважды указывать имя объекта перечисления. Имена теперь выводятся с использованием отражения и системы метаклассов. Кроме того, функции eq () и ismember () были переписаны, чтобы возвращать возвращаемые значения правильной формы для матриц объектов перечисления. И, наконец, функция check_type_safety () была изменена, чтобы сделать ее совместимой с каталогами пакетов (например, пространствами имен).
Кажется, неплохо работает, но дайте мне знать, что вы думаете:
classdef (Sealed) Color
%COLOR Example of Java-style typesafe enum for Matlab
properties (Constant)
RED = Color(1);
GREEN = Color(2);
BLUE = Color(3);
end
methods (Access = private) % private so that you can''t instatiate directly
function out = Color(InCode)
out.Code = InCode;
end
end
% ============================================================================
% Everything from here down is completely boilerplate - no need to change anything.
% ============================================================================
properties (SetAccess=private) % All these properties are immutable.
Code;
end
properties (Dependent, SetAccess=private)
Name;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
methods
function out = eq(a, b) %EQ Basic "type-safe" eq
check_type_safety(a, b);
out = reshape([a.Code],size(a)) == reshape([b.Code],size(b));
end
function [tf,loc] = ismember(a, b)
check_type_safety(a, b);
[tf,loc] = ismember(reshape([a.Code],size(a)), [b.Code]);
end
function check_type_safety(varargin) %CHECK_TYPE_SAFETY Check that all inputs are of this enum type
theClass = class(varargin{1});
for ii = 2:nargin
if ~isa(varargin{ii}, theClass)
error('Non-typesafe comparison of %s vs. %s', theClass, class(varargin{ii}));
end
end
end
% Display stuff:
function display(obj)
disp([inputname(1) ' =']);
disp(obj);
end
function disp(obj)
if isscalar(obj)
fprintf('%s: %s (%d)\n', class(obj), obj.Name, obj.Code);
else
fprintf('%s array: size %s\n', class(obj), mat2str(size(obj)));
end
end
function name=get.Name(obj)
mc=metaclass(obj);
mp=mc.Properties;
for ii=1:length(mp)
if (mp{ii}.Constant && isequal(obj.(mp{ii}.Name).Code,obj.Code))
name = mp{ii}.Name;
return;
end;
end;
error('Unable to find a %s value of %d',class(obj),obj.Code);
end;
end
end
Спасибо, Мейсон