• 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过的句柄

  • 相关阅读:
    Java 自动装箱与拆箱(Autoboxing and unboxing)【转】
    工厂方法和new
    java线程池【转】
    大型网站架构演化过程
    jsp el表达式
    GC垃圾回收
    mysql语句
    String StringBuilder StringBuffer
    粉丝关注数据库表的设计
    ECharts图表之柱状折线混合图
  • 原文地址:https://www.cnblogs.com/usaddew/p/10922206.html
Copyright © 2020-2023  润新知