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

时间:2022-09-11 17:00:55

Lets say I have a superclass called 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

And I have a subclass called Map, in which I want all properties to be read-only once set:

我有一个名为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

How can I make the inherited properties of Rectangle read-only within Map? I want the properties of any stand-alone (non Map) Rectangle object to remain changeable.

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

And also, how can I ensure that some of those properties can take only certain values? i.e. for my purposes a rectangle can have any angle, but I'd expect a map to always have an angle of 0. But if I try to create a set.angle method for Map to ensure that angle can only be 0, I get an error telling me that "Cannot specify a set function for property 'angle' in class 'BackgroundMap', because that property is not defined by that class."

而且,我如何确保其中一些属性只能采用某些值?即为了我的目的,一个矩形可以有任何角度,但我希望一个地图总是有一个0的角度。但如果我尝试为Map创建一个set.angle方法,以确保角度只能是0,我得到一个错误告诉我“无法在类'BackgroundMap'中为属性'angle'指定一个set函数,因为该属性不是由该类定义的。”

1 个解决方案

#1


This seems like a case where you should prefer composition over inheritance.

这似乎是一种情况,你应该更喜欢组合而不是继承。

This idea is mentioned in one of the comments (@Dev-iL), where it's described as "not very OOP". I disagree - although inheritance is the right design in many cases, composition is often preferable. (See here and here for some discussion of that). One of the typical reasons why one might prefer composition is that inheritance exposes the subclass to the details of the superclass, in other words it breaks encapsulation - and that's what's happening in your implementation of Rectangle and Map.

其中一条评论(@ Dev-iL)中提到了这个想法,它被描述为“不是非常OOP”。我不同意 - 虽然在许多情况下继承是正确的设计,但组合通常更可取。 (请参阅此处和此处进行一些讨论)。人们可能更喜欢组合的一个典型原因是继承将子类暴露给超类的细节,换句话说它破坏了封装 - 这就是你的Rectangle和Map实现中发生的事情。

I would suggest that instead of Map inheriting from Rectangle, it should have a Rectangle as a private (maybe hidden) property. So you should think of a map not as being a type of rectangle, but as having an associated rectangle that it delegates some of its functionality to.

我建议不要将Map继承自Rectangle,而应将Rectangle作为私有(可能是隐藏的)属性。所以你应该把地图看成不是一种矩形,而是要有一个相关的矩形,它将它的一些功能委托给它。

Once you've done that, you can then give Map some properties width, height etc, and make them GetAccess=public, SetAccess=private, Dependent. Then within Map, add a get method for each, which just gets the property of the underlying Rectangle and passes it through. Note that Map doesn't need an angle property, as it's always zero.

完成后,您可以为Map提供一些属性宽度,高度等,并使它们成为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

#1


This seems like a case where you should prefer composition over inheritance.

这似乎是一种情况,你应该更喜欢组合而不是继承。

This idea is mentioned in one of the comments (@Dev-iL), where it's described as "not very OOP". I disagree - although inheritance is the right design in many cases, composition is often preferable. (See here and here for some discussion of that). One of the typical reasons why one might prefer composition is that inheritance exposes the subclass to the details of the superclass, in other words it breaks encapsulation - and that's what's happening in your implementation of Rectangle and Map.

其中一条评论(@ Dev-iL)中提到了这个想法,它被描述为“不是非常OOP”。我不同意 - 虽然在许多情况下继承是正确的设计,但组合通常更可取。 (请参阅此处和此处进行一些讨论)。人们可能更喜欢组合的一个典型原因是继承将子类暴露给超类的细节,换句话说它破坏了封装 - 这就是你的Rectangle和Map实现中发生的事情。

I would suggest that instead of Map inheriting from Rectangle, it should have a Rectangle as a private (maybe hidden) property. So you should think of a map not as being a type of rectangle, but as having an associated rectangle that it delegates some of its functionality to.

我建议不要将Map继承自Rectangle,而应将Rectangle作为私有(可能是隐藏的)属性。所以你应该把地图看成不是一种矩形,而是要有一个相关的矩形,它将它的一些功能委托给它。

Once you've done that, you can then give Map some properties width, height etc, and make them GetAccess=public, SetAccess=private, Dependent. Then within Map, add a get method for each, which just gets the property of the underlying Rectangle and passes it through. Note that Map doesn't need an angle property, as it's always zero.

完成后,您可以为Map提供一些属性宽度,高度等,并使它们成为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