matlab实现面向对象编程与matlab本身的定位是冲突的,可能实际的用处并不大,但是依然值得学习一下。本文系原创,以一则简单实例实现经典的命令模式,供新手学习参考。
STEP 0 新建一个文件夹
新建一个文件夹作为本例的工作文件夹。本例的每一个“类”,都被保存为一个独立的.m文件,存放在该文件夹中。
STEP 1 构建命令执行的对象
对象是类的具体实例。此处构建的实际是可用于命令执行的类。例如,一个学生必然有自己的名字和年龄,这里学生就可以抽象为一个类,学生的名字和年龄就是这个类的属性,更改学生的名字和年龄就是可执行的“命令”。代码如下:
classdef Student < handle
properties(Access=public)
name string
age double{mustBeNonnegative}
end
methods
function obj=Student(Name,Age)
obj.name=Name;
obj.age=Age;
end
function selfIntroduc(obj)
disp([obj.name num2str(obj.age)])
end
end
end
STEP 2 构建命令基类(命令接口)
matlab支持抽象类和类的继承。通过定义一个抽象的基类实现“接口”功能。代码如下:
classdef Command < handle
methods(Abstract)
execute(obj,el);
undo(obj);
end
end
STEP 3 将具体命令封装成类(命令类)
为了解耦,需要将具体的命令封装成类,并且把命令执行的对象作为参数进行传递。也就是具体的命令可以由不同的执行对象进行执行,取决于在实例化命令类时传递进来的参数。在这一步,其实把命令内容和命令执行对象进行解耦。通过类的继承,获得统一的命令接口。的代码如下:
%将"改名字"命令封装成类(接口继承自step2 的 Command 类)
classdef cmdChangeName < Command
properties(Access=private)
std Student
oldname
getname
end
methods
function obj=cmdChangeName(Std)
obj.std=Std;
end
function funcGetName(obj,Name)
obj.getname=Name;
end
function execute(obj)
obj.oldname=obj.std.name;
obj.std.name=obj.getname;
end
function undo(obj)
obj.std.name=obj.oldname;
end
end
end
STEP 4 构建命令队列(实例化命令的容器)
同样是为了解耦,需要构建命令队列,也就是将每一个需要执行的实例化的命令按照执行顺序依次收纳到一个容器中。命令模式下,命令队列负责接受需要执行的命令,并将命令加入队列(但是不关心命令的请求者);同时命令队列还负责触发命令的执行(但是不关心命令的执行结果)。也就是这一步实现了命令请求与命令执行的解耦(收到命令请求就加入队列,不管请求者是否还存在;触发命令执行后也不去管命令是否执行完,当然matlab环境下一定会等待命令执行完成)。代码如下:
classdef cmdInvoker
properties(Access=private)
commands myStack
end
methods
function obj=cmdInvoker()
obj.commands=myStack();
end
function runCMD(obj,Cmd)
Cmd.execute();
obj.commands.push(Cmd);
end
function undo(obj)
if obj.commands.size>0
temC=obj.commands.pop;
temC.undo;
else
end
end
end
end
补充说明: matlab没有或类似于“栈”的队列数据形式,本例自定义了一个类似的类。
代码如下:
本段代码参考文章:Matlab 类实例 队列的实现)
classdef myStack <handle
properties (Access = private)
data
count
capacity
end
methods
function obj = myStack(c)
switch nargin
case 0
c=100;
otherwise
end
obj.data = cell(c, 1);
obj.count = 0;
obj.capacity = c;
end
function s=sizeStack(obj)
s=obj.count;
end
function clearStack(obj)
obj.count = 0;
end
function push(obj, el)
if obj.count==obj.capacity
temC=obj.data;
obj.data=cell(obj.capacity+100,1);
obj.capacity=obj.capacity+100;
for iter=1:1:obj.count
obj.data{iter}=temC(iter);
end
else
end
obj.data{obj.count+1} = el;
obj.count = obj.count + 1;
end
function el = pop(obj)
if obj.count == 0
el=[];
else
el = obj.data{obj.count};
obj.count = obj.count - 1;
end
end
function remove(obj)
obj.count=obj.count-1;
end
end
end
STEP 5 客户端(对上述命令模式的检测)
如题,代码如下:
clc;clear all;
%实例化命令执行的对象
S=Student('A',18);
S.selfIntroduc();
%实例化命令队列
I=cmdInvoker();
%实例化需要执行的命令command1和command2
command1=cmdChangeName(S);
command1.funcGetName('B');
command2=cmdChangeName(S);
command2.funcGetName('C');
%将命令添加到命令队列并触发执行(添加和触发执行是同步的,也可以不同步)
%命令队列还会同步记录命令执行前对象的状态,实现撤销或日志功能
I.runCMD(command1);
S.selfIntroduc();
I.runCMD(command2);
S.selfIntroduc();
I.runCMD(command1);
S.selfIntroduc();
I.undo;
S.selfIntroduc();
I.undo;
S.selfIntroduc();