Matlab原型模式(Prototype)

原型(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);

測試結果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章