原型(Prototype)模式的定義如下:用一個已經創建的實例作爲原型,通過複製該原型對象來創建一個和原型相同或相似的新對象。Matlab面向對象編程有兩種類,一種是Value Class,一種是Handle Class,Value對象深拷貝的直接通過賦值語句即可實現(實際上是Lazy Copy),如下所示:
ValueA.m
classdef ValueA
properties
name
end
methods
function obj = ValueA(name)
obj.name = name;
end
end
end
測試代碼:
Handle類是引用類,相當於Java的引用變量,變量指向具體的地址,Handle對象的賦值操作實際上只是淺拷貝,沒有拷貝對象的實際數據。如下圖所示:
RefB.m
classdef RefB < handle
properties
name
end
methods
function obj = RefB(name)
obj.name = name;
end
end
end
測試代碼:
注:一個類如果同時繼承Value類和Handle類時,需要在Value基類加上關鍵詞HandleCompatible,如下所示,其繼承後的類仍然是Value類。
classdef(HandleCompatible) BaseV
end
出了項目的實際需要,需要對handle類進行深拷貝,可以仿照Java的原型模式在handle類中加入clone方法:
RefA.m
classdef RefA < handle
properties
name
refB
end
methods
function obj = RefA()
end
function copyobj = clone(obj)
copyobj = RefA();
copyobj.name = obj.name;
copyobj.refB = obj.refB.clone();
end
end
end
RefB.m
classdef RefB < handle
properties
name
end
methods
function obj = RefB()
end
function copyobj = clone(obj)
copyobj = RefB();
copyobj.name = obj.name;
end
end
end
test1.m
a = RefA();
a.name = 'a-name';
a.refB = RefB();
a.refB.name = 'a-rb-name';
b = a.clone();
b.refB.name = 'b-rb-name';
disp(b.refB.name);
disp(a.refB.name);
結果:
如果要克隆多個屬性,可以藉助meta.class來實現:
RefAA.m
classdef RefAA < handle
properties
name
refBB
end
methods
function obj = RefAA()
end
function copyobj = clone(obj)
copyobj = RefAA();
metaobj = metaclass(obj);
props = {metaobj.PropertyList.Name};
for i = 1:length(props)
prop = obj.(props{i});
if(isa(prop,'handle'))
copyobj.(props{i}) = prop.clone();
else
copyobj.(props{i}) = prop;
end
end
end
end
end
RefBB.m
classdef RefBB < handle
properties
name
end
methods
function obj = RefBB()
end
function copyobj = clone(obj)
copyobj = RefBB();
metaobj = metaclass(obj);
props = {metaobj.PropertyList.Name};
for i = 1:length(props)
prop = obj.(props{i});
if(isa(prop,'handle'))
copyobj.(props{i}) = prop.clone();
else
copyobj.(props{i}) = prop;
end
end
end
end
end
test2.m
a = RefAA();
a.name = 'a-name';
a.refBB = RefBB();
a.refBB.name = 'a-rb-name';
b = a.clone();
b.refBB.name = 'b-rb-name';
disp(b.refBB.name);
disp(a.refBB.name);
運行結果
另外在Matlab R2011a開始,可以使用matlab.mixin.Copyable自動克隆一個對象,可以利用copy函數來實現對象的克隆。這類似於Java的Cloneable類。不過不能對屬性做遞歸的深拷貝,如果要實現深拷貝,需要重寫copyElement方法,代碼如下:
AH.m
classdef AH < matlab.mixin.Copyable
properties
name
bh
end
methods(Access = protected)
function copyobj = copyElement(obj)
copyobj = [email protected](obj);
metaobj = metaclass(obj);
props = {metaobj.PropertyList.Name};
for i = 1:length(props)
prop = obj.(props{i});
if(isa(prop,'handle'))
copyobj.(props{i}) = copy(prop);
end
end
end
end
end
BH.m
classdef BH < matlab.mixin.Copyable
properties
name
end
end
test3.m
a = AH();
a.name = 'a-name';
a.bh = BH();
a.bh.name = 'a-rb-name';
b = copy(a);
b.bh.name = 'b-rb-name';
disp(b.bh.name);
disp(a.bh.name);
測試結果: