MATLAB:将继承的属性设置为只读

MATLAB: Set inherited properties to read-only

假设我有一个名为 rectangle 的超类:

classdef Rectangle
    properties
        width
        height
        x0 = 0
        y0 = 0
        angle = 0
    end
    methods
        function obj = Rectangle(x0, y0, width, height, angle)
            obj.x0 = x0;
            obj.y0 = y0;
            obj.width = width;
            obj.height = height;
            obj.angle = angle;
        end
    end
end

我有一个名为 Map 的子类,我希望其中的所有属性一旦设置为只读:

classdef Map < Rectangle
    properties (SetAccess=private)
        filename
    end
    methods
        function obj = Map(filename)
            % Get info from map using a function that uses geotiffread
            [x0, y0, width, height] = GetInfoFromMap(filename);
            obj = obj@Rectangle(x0, y0, width, height, 0);
            obj.filename = filename;
        end
    end
end

如何在 Map 中将 Rectangle 的继承属性设置为只读?我希望任何独立(非地图)矩形对象的属性保持可变。

另外,我如何确保其中一些属性只能采用特定值?即出于我的目的,矩形可以有任何角度,但我希望地图的角度始终为 0。但是如果我尝试为地图创建 set.angle 方法以确保角度只能为 0,我收到一条错误消息,告诉我 "Cannot specify a set function for property 'angle' in class 'BackgroundMap', because that property is not defined by that class."

这似乎是您应该更喜欢组合而不是继承的情况。

这个想法在评论之一 (@Dev-iL) 中被提及,它被描述为 "not very OOP"。我不同意——尽管在许多情况下继承是正确的设计,但组合通常更可取。 (有关相关讨论,请参阅 here and here)。人们可能更喜欢组合的典型原因之一是继承将子类暴露给超类的细节,换句话说,它破坏了封装——这就是 RectangleMap 的实现中发生的事情。

我建议不要 MapRectangle 继承,它应该有一个 Rectangle 作为私有(可能隐藏)属性。因此,您不应将地图视为一种矩形,而是具有关联的矩形,它委托它的某些功能。

完成后,您可以给 Map 一些属性 widthheight 等,并使它们成为 GetAccess=public, SetAccess=private, Dependent。然后在 Map 中,为每个添加一个 get 方法,它只是获取底层 Rectangle 的 属性 并传递它。请注意 Map 不需要角度 属性,因为它始终为零。

classdef Map < handle
    properties (SetAccess=private)
        filename
    end
    properties (Hidden, GetAccess = private, SetAccess-private)
        rectangleDelegate
    end
    properties (Dependent, GetAccess = public, SetAccess = private)
        width
        height
        x0
        y0
    end
    methods
        function obj = Map(filename)
            % Get info from map using a function that uses geotiffread
            [x0, y0, width, height] = GetInfoFromMap(filename);
            obj.rectangleDelegate = Rectangle(x0, y0, width, height, 0);
            obj.filename = filename;
        end
    end
    methods
        function val = get.width(obj)
            val = obj.rectangleDelegate.width;
        end
        % other gets
    end
end