面向对象编程(Object Oriented Programming,OOP)
1、翻译翻译什么是TMD的对象?
对象是具体的东西,具体事物都有其属性(property),具体事物还有其行为(无论主动还是被动)
2、什么是类
类是对相似对象的抽象,具有相同的属性和行为,例如:f=figure,figure是类,f是对象。
3、面向对象有什么优点?
①面向对象心情愉悦
①面向对象将大问题分解为小的对象,面向过程是通过数据及函数来处理问题,即数据在函数间的流淌。而面向对象是将问题模块化,模块里面有数据也有函数还有模块间的信息传递。因此面向过程更像是细胞,而面向对象更像是复杂的生命体,有各种各样的器官,它们彼此联系和合作完成复杂任务。
②OOP通过组合和信息传递完成任务
OOP是通过不同对象之间的组合和信息传递来完成任务。
③OOP通过继承达到代码复用
④OOP添加或修改模块不会影响其他模块
4、如何定义类
classdef Point2D < handle % Point2D 继承了handle类
properties (Access=privete(只有类的成员方法可以访问)、pritected(本类和子类可以访问)、public暴露给外部)
x
y % 属性
end
properties(Dependent)
r %依赖属性
end
properties(Constant)
pi=3.14 %常量属性
end
properties(Hidden)
pi=3.14 %常量属性
end
methods
function obj=Point2D(x0,y0) % 构造函数,即便没有也可以构造
if nargin==2
obj.x=x0;
obj,y=y0;
set(obj.hFig,'resize','off'....)
else
error('输入数据不够')
end
obj=obj@Point2D(x0,y0);
obj.z=z0;
end
function set.x(obj,val)
if val>0
obj.x=x0;
else
error;
end
end
function r=get.r(obj)
r=sqrt(obj.x^2+obj.y^2);
end
normalize(obj);%仅提供声明
% disp定制对象显示
function disp(0bj)
s=sprintf(....);
s=[s,sprintf(.......)]
disp(s)
end
end
end
5、消息传递(事件和响应)
事件(Event)泛指对象内部状态改变,一个事件的发生会触发一些响应,改变内部状态的对象称为发布者,监听事件并作出响应的对象叫观察者。notify(发布事件)和addlistener(响应函数注册)方法包含在handle类中。事件的定义和notify方法在同一个类中定义,即对象状态改变后该对象负责发布这一事件。发布者定义:
classdef DataSource
addlistener作用是在发布者处登记观察者,需要指定监听事件名称、事件发布者src、回调函数(响应)
h1=addlisterner(eventObject,'EventName',@functionName/@className.methodName)
真正的观察者要把自己的响应函数提供给addlistener方法,即addlistener构建了发布者和监听者的中间层,这样可以避免发布者和观察者的耦合,否则发布者就需要调用观察者的回调函数
观察者回调函数写法:
% 成员方法
classdef Observer < handle
methods
function updateiew(obj,src发布者,data数据)
disp('updataView notified');
end
end
methods(Static)
function updateiew(src发布者,data数据)
disp('updataView notified');
end
end
end
% 普通函数
function updateiew(src发布者,data数据)
disp('updataView notified');
end
发布者不仅要通知事件发生还要传递一定的消息,matlab允许用户自定义一个消息类来传递,该消息类必须继承消息基类event.EventData:
%% 发布者将数据传递给观察者
% 定义数据类,其属性为数据
classdef TimeStamp < event.EventData
properties
ts %时间戳
end
methods
function obj=TimeStamp() %构造函数
obj.ts=[' (' num2str(tempTime(4),'%02.0f') ':'...
num2str(tempTime(5),'%02.0f') ':'...
num2str(tempTime(5),'%02.0f') ')...
'] ;
end
end
end
% 定义发布者,包括事件定义和发布(notify+data)
classdef DataSourcePublisher < handle
events
dataChanged % 事件
end
methods
function queryData(obj) % 访问硬件意味着要更新数据
obj.notify('dataChanged',TimeStamp()); % 发布事件、传递数据
end
end
end
% 定义观察者(主要是定义回调函数)
① 普通函数类
function updateViewSimpleFunc(src,data)
dsip(['data changed at',data.ts]);
end
② 回调函数是静态方法或普通成员方法
classdef Observer < handle
methods(Static)
function updateViewStastic(src,data)
disp(['data changed at',data.ts]);
end
end
methods
function updateView(obj,src,data)
disp(['data changed at',data.ts]);
end
end
end
%% 调用
% 初始化
clc;clear;close;
p=DataSourcePublisher();% 生成发布对象
o=Observer ;% 生成观察者
% 注册监听者
h1=p.addlistener('dataChanged',@updateViewSimpleFun);
h2=p.addlistener('dataChanged',@updateViewStastic);
h3=p.addlistener('dataChanged',@o.updateView);
% 访问硬件
p.queryData();
6、如何定义局部函数
从前面看出类中的属性为数据,成员为方法,这些方法通常是对属性中的数据进行处理,但常常方法需要一些局部辅助函数,它们只是在某一成员方法中调用,作为工具,其只要放在classdef之外即可,也就是对于一些简单的事情我们通过一个类文件夹便可处理,例如@Point。
针对多个类,package管理,+MyPointPackage(包括 @Point2D @Point3D,值得注意的是继承关系前面要加上包的名称,例如 Point3D< MyPointPackage.Point2D),外部使用时可以有两种方法:
① p1=MyPointPackage.Point2D(1,1)
② import MyPointPackage.*; p1=Point2D(1,1)
⑦ 依赖属性
对于单一依赖属性通过声明依赖变量可以计算
对于多重依赖属性需要通过get方法获取