Matlab原型模式

原型(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,使之成为Handle兼容类,如下所示,BaseV仍是Value类,继承后的派生类是Handle类。(如果两个基类都是Value类,至少有一个是Handle兼容类,则继承这两个基类的派生类仍是Value类)

classdef(HandleCompatible) BaseV
end

此外,(1)Handle兼容类的所有基类必须是Handle兼容类。(2) HandleCompatible不能被继承。(3)如果在一个类定义中明确设置了HandleCompatible为false,则该类所有基类中不能有Handle类。(4)如果一个类定义没有明确设置了HandleCompatible特性,而有一个基类是Handle类,则所有基类必须是Handle兼容类。

出于项目的实际需要,需要对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 = copyElement@matlab.mixin.Copyable(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);

测试结果:

注:

1、copy不会调用构造函数

2、copy函数是公有的,不可覆盖的

3、copy函数不会拷贝依赖属性成员

4、copy函数不会默认拷贝动态属性成员(addprop函数),动态属性成员的拷贝功能需要在派生类中实现

5、copy不会复制听众

6、枚举类不能是Copyable的派生类

7、析构函数delete调用copy时,会创建一个合法的副本

8、copy能拷贝已被delete过的句柄

posted on 2019-05-25 13:49  sw-lab  阅读(503)  评论(0编辑  收藏  举报

导航