MATLAB? 将类定义代码组织成模块化代码块,以关键字分隔。所有关键字都有相关联的 end 语句:
classdef…end:所有类组件的定义
properties…end:属性名称声明、属性特性设定、默认值赋值
methods…end:方法签名、方法属性和函数代码的声明
events…end:事件名称和属性的声明
enumeration…end:枚举类的枚举成员和枚举值的声明。
properties、methods、events 和 enumeration
只是 classdef 代码块内的关键字。
classdef (Attributes) ClassName
properties (Attributes)
PropertyName
end
methods (Attributes)
function obj = methodName(obj,arg2,...)
...
end
end
events (Attributes)
EventName
end
enumeration
EnumName
end
end
< handle
是 MATLAB 的抽象类,做父类
classdef 类名 < 继承类
properties %属性
%...
end
methods %方法
%...
end
end
简单的二维点类定义如下:
classdef Point2D < handle
properties %属性
x
y
%...
end
methods %方法
function obj = Point2D(x0,y0)%...
obj.x = x0;
obj.y = y0;
end
function normalize(obj)
r = sqrt(obj.x^2+obj.y^2);
obj.x =obj.x/r;
obj.y =obj.y/r;
end
end
end
表示二维坐标轴上的点,具有 x,y
坐标属性作为其属性
methods 定义了两个方法,一个是 (Constructor) 构造方法;一个是其他的使用函数。其类的成员方法和普通函数区别不大。
注意: 写好类之后,保存调用即可,不能选中类执行,否则会报如下错误:
不同的类类型如下:
p1 = Point2D(1.2,1.0);
p1.x % 1.2000
p1.x = 10;
p1.x % 10
默认属性值
classdef Point2D < handle
properties %属性
x = 0.2;
y = 0.3;
%...
end
支持MATLAB表达式,最好使用固定值。也可以在Constructor中对成员变量进行初始化。
非独立属性
classdef Point2D<handle
properties %属性
x = 0.2;
y = 0.3;
r % r 在Point2D中,通过 x y 计算得出
end
methods %方法
function obj = Point2D(x0,y0)%...
obj.x = x0;
obj.y = y0;
obj.r = sqrt(obj.x^2+obj.y^2);
end
end
end
可以声明成 dependent(非独立)属性,其值可以动态改变
classdef Point2D<handle
properties %属性
x = 0.2;
y = 0.3;
end
properties(Dependent)
r
end
methods %方法
function obj = Point2D(x0,y0)%...
obj.x = x0;
obj.y = y0;
end
function r = get.r(obj) %计算公式需要放在get方法中。
r = sqrt(obj.x^2+obj.y^2);
end
end
end
隐藏属性
properties(Hidden)
查看对象信息,不被显示。 同理可以在成员方法中使用。
不同属性定义如下:
function作为关键词。方法较多,可以将方法单独放一个文件。但需要创建一个独立文件夹
类方法的不同属性:
一个类仅有一个构造函数(Constructor),其函数有且只能有一个返回值,且必须是新的对象。
类的调用:
假设有二维点Point类为基类,这是想拓展其成为三维点Point2类,此时并不需要全部重新构造一个新类,而是在Point的基础上添加需要的属性和方法。
子类会继承所有非私有的属性和方法,可以直接访问和使用,MATLAB默认的继承方法是public,这里我们先不讨论访问权限,只考虑公有继承。
在继承中需要考虑的问题有:
二维点类定义
classdef Point < handle % 表示Point是继承handle的
properties
x = 0
y = 0
end
methods
normalize(obj); % 在类外定义了
function obj = Point(x,y) % 可以使用nargin得到复杂初始化
obj.x = x;
obj.y = y ;
end
function disp(obj) % 自定义显示方法
disp(['x:' num2str(obj.x)]);
disp(['y:' num2str(obj.y)]);
end
end
end
其中: function obj = Point(x,y) 为构造函数,返回的类Point的对象
三维点类定义
classdef Point3D < handle
properties %属性
x = 0
y = 0
z = 0
end
methods %方法
function obj = Point3D(x,y,z)
obj.x = x;
obj.y = y;
obj.z = z;
end
function normalize(obj)
Q = sqrt(obj.x^2+obj.y^2+obj.z^2);
obj.x = obj.x/Q;
obj.y = obj.y/Q;
obj.z = obj.z/Q;
end
function disp(obj)
disp(['x:',num2str(obj.x)]);
disp(['y:',num2str(obj.y)]);
disp(['z:',num2str(obj.z)]);
end
end
end
重新定义三维点类,代码重复率较高,冗余,构造函数也相似,disp 函数也相似。故可以从二维点类继承到三维点类。
通过继承方式从二维点类创建三维点类:
classdef Point3D < Point % 表示Point2是继承Point
properties
z = 0; % 新增一个坐标 z
end
methods
function obj = Point3D(x,y,z)
obj = obj@Point(x,y);
obj.z = z;
end
function normalize(obj)
Q = sqrt(obj.x^2+obj.y^2+obj.z^2);
obj.x = obj.x/Q;
obj.y = obj.y/Q;
obj.z = obj.z/Q;
end
function disp(obj)
disp@Point(obj)
disp(['z:' num2str(obj.z)]);
end
end
end
其中Point2D为父类(Parent Class)Point3D为子类。
添加新属性
子类的构造函数
obj = obj@Point(x,y)
; ,这里右边的obj表示Point返回一个obj对象,给左边的obj赋值之后,obj是一个Point2对象,z为空。调用父类方法:
父类函数名 + @ + 父类类名 + (obj,其他参数)
p3 = Point3D();
isa(p3,'Point')
子类的构造函数需要先调用父类的 Constructor。
子类中如何调用父类同名方法
相同函数foo,子类对父类的方法进行了扩展。
同样的方法被不同的对象调用产生不同的形态。如上三维点类和二维点类的print函数。
类之间的基本关系:继承、组合和聚集
B可不可以继承A,要看其是否拥有A的属性和方法。例:企鹅和鸟的类区别。
类的组合(Composition):多个类的组合,而不是多个类的多重继承。
classdef Head<handle
properties
eye
nose
mouth
ear
end
methods
function obj = Head()
obj.eye = Eye();
obj.nose = Nose();
obj.mouth = Mouth();
obj.ear = Ear();
end
end
end
%避免使用如下 多重继承
classdef Head<Eye&Nose&Mouth&Ear
%..
end
Handle类的set和get方法
set方法给对象属性赋值
classdef A < handle
properties
a
end
methods
function set.a(obj,val)
if val > 0
obj.a = val;
else
error('a must be positive');
end
end
end
end
在命令行给a负值,则会报错
>> obj = A();
>> obj.a = -10
错误使用 A/set.a (line 10)
a must be positive
外部赋值,会调用set函数 ;内部则不会,但在properties部分设置默认值时需要验证set的有效性。
一个属性的set方法尽量不要访问其他属性,(Order Dependency),若需要则将其属性设置为Dependent。
get方法
function val = get.b(obj)
val = obj.b;
disp('getter called');
end
Matlab也可以写面向对象的代码,首先表现在可以定义类,可以继承,使用类(class)有很多好处,其中一个重要的好处便是解决变量名冲突和让函数、对象的结构清晰。class的static function可以在不定义类的实例直接调用类的成员函数,比如:
classdef tools < handle
methods (Static = true)
function a = test(b, c)
a = b + c;
end
end
end
然后可以直接通过 a = tools.test(b, c)
调用函数。
《MATLAB面向对象编程-从入门到设计模式(第2版)》