2015-05-07 2 views
2

Допустим, у меня есть суперкласс называется прямоугольник:MATLAB: Set наследуемые свойства только для чтения

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 = [email protected](x0, y0, width, height, 0); 
      obj.filename = filename; 
     end 
    end 
end 

Как я могу наследовать свойства Rectangle только для чтения в пределах карты? Я хочу, чтобы свойства любого автономного объекта (non Map) Rectangle оставались изменчивыми.

А также, как я могу гарантировать, что некоторые из этих свойств могут принимать только определенные значения? т.е. для моих целей прямоугольник может иметь любой угол, но я бы ожидал, что карта всегда будет иметь угол 0. Но если я попытаюсь создать метод set.angle для Map, чтобы гарантировать, что угол может быть равен 0, я получаю ошибка, сообщающая мне, что «Невозможно указать функцию set для свойства« angle »в классе« BackgroundMap », потому что это свойство не определено этим классом».

+1

Как бы вы сделали что-то подобное на других языках? Не могли бы вы переопределить свойства суперкласса, используя более ограничительные квалификаторы (например, 'private' вместо' public'/'protected')? Что касается MATLAB - общий подход (хотя и не очень простой, который мне не нравится) заключался бы в том, чтобы разбить отношение наследования и сделать «Map» своим классом, который имеет свойство, которое указывает на определенный «Прямоугольник» и расширьте 'Rectangle' от' handle'. Еще один вопрос - предположим, что вы унаследовали свойства в «Map», будут ли они исправлены или, возможно, сменны, следует ли выполнять надверхность? –

+0

Я не знаю, MATLAB - это мое первое знакомство с ООПом, за исключением очень короткого введения в питоне, который никогда не отваживался до наследования. Я знаю, что MATLAB не является идеальным языком ООП, но это то, что мы должны использовать на работе. Честно говоря, я только предположил, что вы сможете установить ограничения на унаследованные свойства, но, возможно, это не так. Спасибо за намек на нарушение наследства. – EddyTheB

ответ

2

Это похоже на случай, когда вы предпочитаете композицию над наследованием.

Эта идея упоминается в одном из комментариев (@ Dev-iL), где описывается как «не очень ООП». Я не согласен - хотя наследование является правильным дизайном во многих случаях, композиция часто предпочтительнее. (См. here и here для обсуждения этого). Одной из типичных причин, почему можно предпочесть композицию, является то, что наследование предоставляет подкласс деталям суперкласса, другими словами, он разрушает инкапсуляцию - и это то, что происходит в вашей реализации Rectangle и Map.

Я бы предположил, что вместо Map, унаследовавшего от Rectangle, он должен иметь Rectangle как частную (возможно, скрытую) собственность. Таким образом, вы должны думать, что карта не является типом прямоугольника, а имеет связанный прямоугольник, который делегирует некоторые из его функциональных возможностей.

После того, как вы сделали это, вы можете дать Map некоторые свойства width, height и т.д., и сделать их 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 
+0

Спасибо. Это решение работает, и объяснение улучшило мое понимание ООП.Единственное изменение, которое я сделал, - сделать GetAccess of rectangleDelegate общедоступным, потому что я хочу получить доступ к некоторым из методов, содержащихся в Rectangle (я оставил методы из моего первоначального примера для краткости). Например, если я хочу область карты, тогда я могу сделать Map.rectangleDelegate.area, где область является методом класса Rectangle. Я полагаю, что я мог бы написать небольшие однострочные функции для Map, которые вызывают те же функции в Rectangle. – EddyTheB

+1

@EddyTheB Конечно, это ваш выбор, но я бы рекомендовал вам не делать этого. Весь смысл шаблона Delegate заключается в том, что вы не публиковате делегата публично, а вместо него - внутри себя - делегируете ему функции. Пользователь внешнего класса не должен знать, что он есть. Я бы рекомендовал добавить дополнительные свойства к 'Map', а затем написать одну строку' get', которые вызывают Rectangle и пропускают результаты. –

+0

Достаточно справедливо, я сделаю это без. Благодарю. – EddyTheB

Смежные вопросы