这里写目录标题
1 入门
1.1 如何把面条抽象成Class
以面条为例。
classdef Noodle < handle
properties
type
state
end
methods
function boil(obj)
obj.state = 'done';
end
end
end
其中Noodle是类的名称,type和state是类的property,类的属性,也可以称作成员变量。
将其类定义的保存名为Noodle.m,与类同名。
调用类的方法
noodle = Noodle(); %调用构造函数的创建对象obj。
noodle.boil(); %调用成员方法boil,noodle属性改变。
1.2 文件类
classdef FileClass < handle
properties
name
path
format
data
fID
end
methods
function obj = FileClass(name,path)
obj.name = name;
obj.path = path;
obj.open();
obj.read();
end
function open(obj)
fullpath = strcat(obj.path,filesep,obj.name);
obj.fID = fopen(fullpath);
end
function read(obj)
obj.data = textscan(obj.fID,'%s %s %s'); %假定数据文件为两列
end
function delete(obj)
fclose(obj.fID);
disp('file closed');
end
end
end
所有的属性和操作均为public,可以直接访问文件的数据属性。
fileobj = FileClass(filename,path);
a = fileobj.data;%赋值给a
面向对象编程的优点:
- 将一个复杂的大问题分解为一个个小的模块。
- 通过组合和信息传递完成相应的任务。
- 通过继承实现代码复用
- 修改和添加模块不影响其他模块
2 基于MATLAB的面向对象编程入门
2.1 如何定义一个类(Class)
MATLAB可以通过whos检查变量所属的类。
用户可以设计自己的类。
classdef Point2D<handle
properties %属性
%...
end
methods %方法
%...
end
end
- MATLAB的所有Class均以classdef开始
- classdef后紧跟类名,
- <handle 是MATLAB的抽象类,做父类
如简单的二维点类定义如下
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)构造方法* ;一个是其他的使用函数。其类的成员方法和普通函数区别不大。
2.2 创建一个对象
p1 = Point2D(1.2,1.0);
p2 = Point2D(2.0,5.0);
属性可以是double标量,矩阵甚至是GUI对象。
2.3 类的属性
2.3.1 如何访问对象的属性
p1 = Point2D(1.2,1.0);
p1.x
p1.x = 10;
p1.x
通过Dot运算符实现
2.3.2 默认属性值
classdef Point2D<handle
properties %属性
x = 0.2;
y = 0.3;
%...
end
支持MATLAB表达式,最好使用固定值。也可以在Constructor中对成员变量进行初始化。
同时是属性可以实现一些特定属性。
- 常量(Constant)
properties(Constant)不可修改。 - 非独立属性
classdef Point2D<handle
properties %属性
x = 0.2;
y = 0.3;
r%受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
function normalize(obj)
obj.x =obj.x/obj.r;
obj.y =obj.y/obj.r;
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
function normalize(obj)
obj.x =obj.x/obj.r;
obj.y =obj.y/obj.r;
end
end
end
- 隐藏属性
properties(Hidden)
查看对象信息,不被显示。
同理可以在成员方法中使用。
2.4 类的方法
2.4.1 定义类的方法
function作为关键词。
方法较多,可以将方法单独放一个文件。
但需要创建一个独立文件夹
2.4.2 调用类的方法
点调用和函数调用形式:
obj.memberFunction(arg1,arg2) 等价于 memberFunction(obj,arg1,arg2)
最好使用点调用。
- 方法的签名
obj必须作为方法的参数,是其对所有对象均能作用,同时作为在MATLAB中唯一性方法的签名(signature),不同类下的同一命名的函数可以同时使用。
2.5 类的构造函数
一个类仅有一个构造函数(Constructor)。
其函数有且只能有一个返回值,且必须是新的对象。
-
构造函数中可以给属性赋值。
-
通过nargin使构造函数接收不同参数的输入。
-
默认构造函数(Default Constructor:不带任何参数的构造函数。
-
不创建构造函数,MATLAB会给一个默认值。不接受任何参数。
2.6 类的继承
继承是OOP中最重要的概念之一。
假设两个独立的类,二维点和三维点的类。
分别定义如下
-二维点类定义
classdef Point2D<handle
properties %属性
x
y
end
methods %方法
function obj = Point2D(x0,y0)
obj.x = x0;
obj.y = y0;
end
function print(obj)
disp(['x = ',num2str(obj.x)]);
disp(['y = ',num2str(obj.y)]);
end
end
end
- 三维点类定义
classdef Point3D<handle
properties %属性
x
y
z
end
methods %方法
function obj = Point3D(x0,y0,z0)
obj.x = x0;
obj.y = y0;
obj.z = z0;
end
function print(obj)
disp(['x = ',num2str(obj.x)]);
disp(['y = ',num2str(obj.y)]);
disp(['z = ',num2str(obj.z)]);
end
end
end
重新定义三维点类,代码重复率较高,冗余,构造函数也相似,print函数也相似。
故可以从二维点类继承到三维点类。
通过继承方式从二维点类创建三维点类。
classdef Point3D<Point2D
properties %属性
z
end
methods %方法
function obj = Point3D(x0,y0,z0)
obj = obj@Point2D(x0,y0);
obj.z = z0;
end
function print(obj)
print@Point2D(obj);
disp(['z = ',num2str(obj.z)]);
end
end
end
其中Point2D为父类(Parent Class)Point3D为子类。
p3 = Point3D();
isa(p3,'Point2D')
值为1,因为三维点是二维点的一种。
子类的构造函数需要先调用父类的Constructor。
-子类中如何调用父类同名方法
相同函数foo,子类对父类的方法进行了扩展。
多态(Polymorphism)
同样的方法被不同的对象调用产生不同的形态。如上三维点类和二维点类的print函数。
2.7 类之间的基本关系:继承、组合和聚集
- 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
- 组合的聚集关系(Aggregation)
2.8 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
将程序变得向后兼容。
% % classdef Record < handle
% % properties
% % date
% % end
% % end
% 将其名字改的更有意义
% 改为timeStamp
classdef Record< handle
properties(Dependent,Hidden)
date
end
properties
timeStamp %新属性
end
methods
function set.date(obj,val)
obj.timeStamp = val;
end
function val = get.date(obj)
val = obj.timeStamp;
end
end
end
在不修改外部程序情况下实现对新类的定义 。
但set和get方法耗时较长,避免如下的无意义的set和get 定义
classdef A < handle
properties
var
end
methods
function set.var(obj,var)
obj.var = var;
end
function var = get.var(obj)
var = obj.var;
end
end
end
2.9 类的属性和方法的访问权限
- public,protected,private
控制类公开的内容,避免不必要内容。
根据关键词“Access= private,protected,public”进行声明属性和方法的可访问性。 - private
表示仅该类的成员方法可以访问此数据。 - protected
表示仅该类和其子类可以访问此数据 - public
均可见
属性的访问权限可以细分为SetAccess和GetAccess
问题:私有成员数据子类不可见,是不能继承?
举例:访问权限设置-银行账户
- 更加细化的控制访问权限
通过Access中指定类名实现。
(Account = {?BankManager})
类似与C++的friend关键词,但此仅针对一个属性或方法进行实现。
2.10 clear classes
- clear obj
清除对象 - clear classes
2.11 对象根据类定义的改变自动更新
不需要clear classes
R2014b版之后
《MATLAB面向对象编程-从入门到设计模式(第2版)》