Свойства и методы, заданные классом, образуют интерфейс, который определяет, как пользователи классов взаимодействуют с объектами класса. При создании группы связанных классов интерфейсы определяют общий интерфейс для всех этих классов. Фактические реализации интерфейса могут отличаться от одного класса к другому.
Рассмотрим набор классов, предназначенных для представления различных типов графиков. Все классы должны реализовать Data
свойство, содержащее данные, используемые для генерации графика. Однако форма данных может значительно отличаться от одного типа графика к другому. Каждый класс может реализовать Data
свойство по-разному.
Те же различия применяются и к методам. Все классы могут иметь draw
метод, который создает график, но реализация этого метода изменяется с типом графика.
Основная идея класса интерфейса состоит в том, чтобы задать свойства и методы, которые каждый подкласс должен реализовать, не определяя фактическую реализацию. Этот подход позволяет применить последовательный интерфейс к группе связанных объектов. Когда вы добавляете больше классов в будущем, интерфейс остается неизменным.
Этот пример создает интерфейс для классов, используемых для представления специализированных графиков. Интерфейс является абстрактным классом, который задает свойства и методы, которые должны реализовать подклассы, но не задает, как реализовать эти компоненты.
Этот подход обеспечивает применение последовательного интерфейса, обеспечивая при этом необходимую гибкость для реализации внутренней работы каждого специализированного подкласса по-разному.
В этом примере папка пакета содержит интерфейс, производные подклассы и служебную функцию:
+graphics/GraphInterface.m % abstract interface class +graphics/LineGraph.m % concrete subclass
The graph
класс задает следующие свойства, которые должны задавать подклассы:
Primitive
- Указатель на графический объект, используемый для реализации специализированного графика. Пользователь класса не должен непосредственно обращаться к этим объектам, поэтому это свойство имеет protected
SetAccess
и GetAccess
.
AxesHandle
- Указатель на оси, используемые для графика. Специализированные graph
объекты могут задать свойства объекта осей. Это свойство имеет protected
SetAccess
и GetAccess
.
Data
- Все подклассы GraphInterface
класс должен хранить данные. Тип данных изменяется, и каждый подкласс определяет механизм хранения. Пользователи подкласса могут изменять значения данных таким образом, чтобы это свойство имело права общедоступного доступа.
The GraphInterface
именует три абстрактных метода, которые должны реализовывать подклассы. The GraphInterface
класс также предлагает в комментариях, что каждый конструктор подкласса должен принимать пары графика data и имя свойства/property значение для всех свойств класса.
Конструктор подкласса - Принимает пары данных и P/V и возвращает объект.
draw
- Используется для создания примитива чертежа и визуализации графика данных в соответствии с типом графика, реализованного подклассом.
zoom
- Реализация метода масштабирования путем изменения осей CameraViewAngle
свойство. Интерфейс предполагает использование camzoom
функция для консистентности среди подклассов. Кнопки масштаба, созданные addButtons
статический метод использует этот метод в качестве коллбэка.
updateGraph
- Метод, вызываемый set.Data
метод для обновления нанесенных на график данных каждый раз, когда Data
изменения свойств.
Пакет классов, которые получают из GraphInterface
абстрактный класс реализует следующее поведение:
Создание образца специализированного GraphInterface
объект (объект подкласса) без визуализации графика
Установка какого-либо свойства объекта или его отсутствия при создании специализированного GraphInterface
объект
Изменение любого свойства объекта автоматически обновляет текущий отображаемый график
Разрешение каждой специализированной GraphInterface
объект для реализации любых дополнительных свойств, требуемых для предоставления пользователям классов контроля над этими характеристиками.
The GraphInterface
класс является абстрактным классом, который задает методы и свойства, используемые подклассами. Комментарии в абстрактном классе описывают предполагаемую реализацию:
classdef GraphInterface < handle % Abstract class for creating data graphs % Subclass constructor should accept % the data that is to be plotted and % property name/property value pairs properties (SetAccess = protected, GetAccess = protected) Primitive AxesHandle end properties Data end methods (Abstract) draw(obj) % Use a line, surface, % or patch graphics primitive zoom(obj,factor) % Change the CameraViewAngle % for 2D and 3D views % use camzoom for consistency updateGraph(obj) % Update the Data property and % update the drawing primitive end methods function set.Data(obj,newdata) obj.Data = newdata; updateGraph(obj) end function addButtons(gobj) hfig = get(gobj.AxesHandle,'Parent'); uicontrol(hfig,'Style','pushbutton','String','Zoom Out',... 'Callback',@(src,evnt)zoom(gobj,.5)); uicontrol(hfig,'Style','pushbutton','String','Zoom In',... 'Callback',@(src,evnt)zoom(gobj,2),... 'Position',[100 20 60 20]); end end end
The GraphInterface
класс реализует метод набора свойств (set.Data
) для мониторинга изменений в Data
свойство. Альтернативой является определение Data
свойство как Abstract
и разрешить подклассам определять, реализовывать ли метод доступа к набору для этого свойства. The GraphInterface
класс задает метод доступа к набору, который вызывает абстрактный метод (updateGraph
, который должен реализовать каждый подкласс). The GraphInterface
интерфейс накладывает определенный проект на весь пакет классов, не ограничивая гибкость.
The addButtons
метод добавляет кнопки для zoom
методы, которые должен реализовать каждый подкласс. Использование метода вместо обычной функции позволяет addButtons
для доступа к защищенным данным класса (указатель на оси). Используйте объект zoom
метод как кнопочный коллбэк.
function addButtons(gobj) hfig = get(gobj.AxesHandle,'Parent'); uicontrol(hfig,'Style','pushbutton',... 'String','Zoom Out',... 'Callback',@(src,evnt)zoom(gobj,.5)); uicontrol(hfig,'Style','pushbutton',... 'String','Zoom In',... 'Callback',@(src,evnt)zoom(gobj,2),... 'Position',[100 20 60 20]); end
Этот пример задает только один подкласс, используемый для представления простого линейного графика. Это происходит от GraphInterface
, но предоставляет реализации для абстрактных методов draw
, zoom
, updateGraph
, и его собственный конструктор. Базовый класс GraphInterface
и подкласс все содержатся в пакете (graphics
), который необходимо использовать для ссылки на имя класса:
classdef LineGraph < graphics.GraphInterface
The LineGraph
класс реализует интерфейс, заданный в GraphInterface
Класс и добавляет два дополнительных свойства - LineColor
и LineType
. Этот класс определяет начальные значения для каждого свойства, поэтому установка значений свойств в конструкторе является необязательной. Можно создать LineGraph
объект без данных, но вы не можете создать графиков из этого объекта.
properties LineColor = [0 0 0]; LineType = '-'; end
Конструктор принимает struct
с x
и y
координатные данные и пары имя/значение свойства:
function gobj = LineGraph(data,varargin) if nargin > 0 gobj.Data = data; if nargin > 2 for k=1:2:length(varargin) gobj.(varargin{k}) = varargin{k+1}; end end end end
The LineGraph
draw
метод использует значения свойств, чтобы создать line
объект. The LineGraph
класс хранит line
указатель как защищенные данные класса. Чтобы поддержать использование никаких входных параметров для конструктора классов, draw
проверяет Data
свойство для определения, пуст ли он перед продолжением:
function gobj = draw(gobj) if isempty(gobj.Data) error('The LineGraph object contains no data') end h = line(gobj.Data.x,gobj.Data.y,... 'Color',gobj.LineColor,... 'LineStyle',gobj.LineType); gobj.Primitive = h; gobj.AxesHandle = get(h,'Parent'); end
The LineGraph
zoom
метод следует комментариям в GraphInterface
класс, который предлагает использовать camzoom
функция. camzoom
обеспечивает удобный интерфейс для масштабирования и правильно работает с кнопками, созданными addButtons
способ.
Методы набора свойств обеспечивают удобный способ автоматического выполнения кода, когда значение свойства изменяется впервые в конструкторе. (См. «Методы набора свойств».) The linegraph
класс использует методы set, чтобы обновить line
примитивные данные (которые вызывают перерисовку графика) всякий раз, когда изменяется значение свойства. Использование методов набора свойств предоставляет способ быстро обновить график данных, не требуя вызова draw
способ. The draw
метод обновляет график путем сброса всех значений, чтобы соответствовать текущим значениям свойств.
Три свойства используют методы набора: LineColor
, LineType
, и Data
. LineColor
и LineType
свойства, добавленные LineGraph
Классы и специфичны для line
примитив, используемый этим классом. Другие подклассы могут задать различные свойства, уникальные для их специализации (для примера FaceColor
).
The GraphInterface
класс реализует Data
метод набора свойств. Однако GraphInterface
класс требует, чтобы каждый подкласс определял метод, называемый updateGraph
, который обрабатывает обновление данных графика для конкретного используемого примитива чертежа.
Вот LineGraph
определение класса.
classdef LineGraph < graphics.GraphInterface properties LineColor = [0 0 0] LineType = '-' end methods function gobj = LineGraph(data,varargin) if nargin > 0 gobj.Data = data; if nargin > 1 for k=1:2:length(varargin) gobj.(varargin{k}) = varargin{k+1}; end end end end function gobj = draw(gobj) if isempty(gobj.Data) error('The LineGraph object contains no data') end h = line(gobj.Data.x,gobj.Data.y,... 'Color',gobj.LineColor,... 'LineStyle',gobj.LineType); gobj.Primitive = h; gobj.AxesHandle = h.Parent; end function zoom(gobj,factor) camzoom(gobj.AxesHandle,factor) end function updateGraph(gobj) set(gobj.Primitive,... 'XData',gobj.Data.x,... 'YData',gobj.Data.y) end function set.LineColor(gobj,color) gobj.LineColor = color; set(gobj.Primitive,'Color',color) end function set.LineType(gobj,ls) gobj.LineType = ls; set(gobj.Primitive,'LineStyle',ls) end end end
LineGraph
КлассThe LineGraph
класс задает простой API, заданный как graph
базовый класс и реализует свой специализированный тип графика:
d.x = 1:10; d.y = rand(10,1); lg = graphics.LineGraph(d,'LineColor','b','LineType',':'); lg.draw; lg.addButtons;
Нажатие кнопки Zoom In показывает zoom
способ обеспечения коллбэка для кнопки.
Изменение свойств обновляет график:
d.y = rand(10,1); lg.Data = d; lg.LineColor = [0.9,0.1,0.6];
Теперь нажмите Zoom Out и посмотрите новые результаты: