Wednesday, May 14, 2008

matlab FIFO 队列 queue 类的全过程

8.9 面向对象编程
8.9.2 面向对象编程应用示例

【例 8.9.2 -1 】本例演示:创建“先进先出” FIFO 队列 queue 类的全过程。在本例中,读者应充分注意:构架域( Fields of a structure array )和定义在其上的方法函数( Method function )之间的关系。

(1)建立类目录 @queue
(2)选择构架数组为 queue 类的数据结构
(3)创建构造函数 queue.m
[@queue\queue.m]
function q=queue(v)
%@QUEUE\QUEUE queue class constructor function
% 调用格式
% q=queue 创建一个 " 空 " 队列对象 .
% q=queue(v) 创建包含变量 v 的队列对象。
superiorto( 'double' , 'sparse' , 'struct' , 'cell' , 'char' , 'inline' , 'sym' );
% 使 queue 对象具有最高优先级 <6>
if nargin>1;error( 'Too many arguments.' ); end ;
if nargin==0 % 没有输入宗量情况
q.value=[]; % value 域被赋“空阵”
q.name= '' ; % name 域不给任何字符
q=class(q, 'queue' ); % 给变量 q 挂上 queue 标签
elseif isa(v, 'queue' ); % 输入宗量是同类对象情况
q=v; % 直接把输入量赋给 q
else % 非同类输入宗量情况
q.value=v; % 在 value 域中放置输入对象 v 的内容
q.name=inputname(1); % 在 name 域中放置输入对象名 v 字符
if isempty(q.name) % 假如输入量无名
q.name=[ '(' class(v) ')' ]; % 就采用 v 本身的类名
end

q=class(q, 'queue' ); % 给变量 q 挂上 queue 标签 <20>
end

(4)为 queue 对象编写显示函数 display.m
[@queue\display.m]
function display(q,ki,kj)
%QUEUE\DISPLAY command window display of a queue object.
% 调用格式
% display(q) 笼统显示整个队列
% display(q,ki) 单下标法显示具体队列元素的内容
% display(q,ki,kj) 双下标法显示具体队列元素的内容
if nargin==0;error( ' 缺少输入宗量,即被显示对象 ! ' ); end
switch nargin
case 1 % 显示整个队列
[m,n]=size(q);
vname=inputname(1); % 被显示对象 q 的名称
if isempty(vname) % 显示对象若无名称
fprintf( 'ans=\n' ); % 按 MATLAB 惯例,屏幕显示 ans 缺省名
elseif fprintf( '%s=\n' ,vname); % 对象有名称时,则屏幕以字符串形式显示名称
end ;

if isempty(q) % 假如被显示对象为“空”
fprintf( ' [ empty ' ) %<17>
fprintf( '%s' ,class(q)) %<18>
fprintf( ' ]\n\n' ); %<19>
elseif m*n==1; % 被显示对象今包含一个“元素”时
fprintf( ' %s: ' ,q.name); % 屏幕先以字符串形式显示所存放对象的名称
disp(q.value); % 紧接着,不换行,显示所存放对象的内容
fprintf( '\n' );
else % 被显示对象今包含多个“元素”时
fprintf( ' [ %d*%d ' ,m,n) % 以下 3 条指令只显示队列“元素”排列 <25>
fprintf( '%s' ,class(q)) %<26>
fprintf( ' ]\n\n' ); %<27>
end

case 2 % 单下标法显示具体队列元素的内容
disp([ 'The content of ' ,inputname(1), '(' ,int2str(ki), ')' ])
disp([ 'is a ''' ,class(q(ki).value), ''' object' ])
fprintf( ' %s=\n' ,q(ki).name);
disp(q(ki).value);
fprintf( '\n' );
case 3 % 双下标法显示具体队列元素的内容
disp([ 'The content of ' ,inputname(1), '(' ,int2str(ki), ',' ,int2str(kj), ')' ])
disp([ 'is a ''' ,class(q(ki,kj).value), ''' object' ])
fprintf( ' %s=\n' ,q(ki,kj).name);
disp(q(ki,kj).value);
fprintf( '\n' );
end

(5)编写重载函数 isempty.m
[@queue\isempty.m]
function f=isempty(q)
%@QUEUE\ISEMPTY True for an empty queue object.
f=0;
[m,n]=size(q);
if m*n==1;
if isempty(q.value) & isempty(q.name) %<6>
f=1;
end ;
end ;

(6)编写“入队”、“离队”函数
[ @queue\comein.m]
function q=comein(p,varargin)
% @QUEUE\COMEIN a variable comes to the end of a queue.
% 调用格式
% comein(p,a,b,...) 使输入宗量 a,b 等排在 p 之后形成新队列,
% 其名沿用 p 位置上的输入队列名 .
% q=comein(p,a,b,...) 使输入宗量 a,b 等排在 p 之后形成新队列 q .
if nargin<2 error( 'comein needs at least two arguments.' ); end ;
if ~isa(p, 'queue' ) error([inputname(1), ' is not a queue' ]); end ;
q0=p;
qzzy=class(p); % 获取第一输入宗量的类别字符串 <10>
for i=1:length(varargin)
temp=varargin{i};
s=eval([qzzy, '(temp)' ]); % 使后来元素成为与第一输入宗量相同的类别 <13>
s.name=inputname(i+1);
if isempty(s.name) % 假如某输入宗量本身无名称
s.name=[ '(' class(temp) ')' ]; % 则把它的类别名作为名称使用
end

if isempty(q0) % 假如前队列是“空”队列
q0=s; % 则直接进入队列
else % 假如前队列非“空”
q0=[q0 s]; % 则新变量排在队尾
end
end

if nargout==0; % 假如没有输出宗量
assignin( 'caller' ,inputname(1),q0); % 新队列沿用第一个输入队列名
evalin( 'caller' ,inputname(1));
else % 假如有输入输出宗量
q=q0; % 新队列名为 q
end

[@queue\goout.m]
function [n,v,q]=goout(p)
% @QUEUE\GOOUT removes the first(the front) element from a queue.
% 调用格式
% goout(p) 从队列 p 中的第一个元素离队 .
% v=goout(p) v 是从 p 队列中移出的那第一个元素的“值”
% [n,v]=goout(p) n,v 分别 是从 p 队列中移出的那第一个元素的“名称”和“值”
% [n,v,q]=goout(p) n,v 分别 是从 p 队列中移出的那第一个元素的“名称”和“值”
% q 是被移去第一个元素后的新队列
if nargin==0 ;error( 'No queue specifide.' ); end ;
if nargout>3;error( 'Too many output arguments.' ); end ;
if nargin>1 error( 'Too many input arguments.' ); end ;
if ~isa(p, 'queue' );error([inputname(1), ' is not a queue.' ]); end ;
if isempty(p)
q1=p;
else
[m,n]=size(p);
v1=p(1).value;n1=p(1).name;
if m*n==1
q1=queue;
else
q1=p(2:end);
end
end

if nargout<3;
assignin( 'caller' ,inputname(1),q1);
end ;

if nargout==0,
evalin( 'caller' ,inputname(1));
end
if nargout>=1;v=v1; end ;
if nargout>=2;n=n1; end ;
if nargout==3;q=q1; end ;

【 * 例 8.9.2 -2 】本例的目的:一,检验例 8.9.2-1 所编写的程序的正确性;二,演示所设计的新类是如何被运作的。

(1)创建一个队列对象,并显示。
qe='Hello! 你好 ! '; % 字符串
Q=queue(qe) % 生成队列对象 Q ,并显示
Q=
qe: Hello! 你好 !

(2)类别检查和是否对象判断
class(Q) % 类别检查
isobject(Q) % 是否对象判断
isa(Q,'queue') % 是否队列判断
ans =
queue
ans =
1
ans =
1

(3)是否“空”队列判断
isempty(Q)
ans =
0

【 * 例 8.9.2 -3 】本例目的:一,演示“入队”、“离队”函数的调用方法;二,演示 @queue\display 显示队列具体元素细节的功能。

(1)利用“入队”函数,使队列变长。
a=[1,2,3;4,5,6];b{1}='This';b{2}=' is ';b{3}='a cell array';
comein(Q,a,b) % 增长队列,并显示整个队列的“宏观”情况
Q=
[ 1*3 queue ]

(2)显示队列 Q 中具体元素的内容
display(Q,2) % 给出 Q 队列第 2 个元素的类别、内容:变量名和值
The content of Q(2)
is a 'double' object
a=
1 2 3
4 5 6

(3)把 Q 队列第 1 个元素和其余部分分离,并生成新队列 QQ
[nn,vv,QQ]=goout(Q)
nn =
qe
vv =
Hello! 你好 !
QQ=
[ 1*2 queue ]

(4)采用双下标法,显示 QQ(1,2) 的内容
display(QQ,1,2)
The content of QQ(1,2)
is a 'cell' object
b=
'This' ' is ' 'a cell array'

【例 8.9.2 -4 】利用指令 methods 可以获知对任何类定义的(在类目录上的)所有方法函数。
methods queue
Methods for class queue:

comein display goout isempty queue

0 comments: