インターフェイスのスーパークラスの定義
インターフェイス
クラスで定義されたプロパティとメソッドは、クラスのユーザーがそのクラスのオブジェクトどのようにやり取りするかを決めるインターフェイスを形成します。関連するクラスのグループを作成する場合には、インターフェイスでこれらのクラスすべてに共通のインターフェイスを定義します。インターフェイスの実際の実装がクラスによって異なっていてもかまいません。
さまざまな種類のグラフを表すために設計されたクラスのセットを考えます。すべてのクラスで、グラフの作成に使用するデータを含む Data プロパティを実装しなければなりません。ただし、データの形式は、グラフの種類によって大きく異なります。それぞれのクラスに、異なる方法で Data プロパティを実装できます。
同様の違いはメソッドに適用されます。すべてのクラスはグラフを作成する draw メソッドをもつことができますが、このメソッドの実装はグラフの種類によって異なります。
インターフェイス クラスの基本的な考え方は、各サブクラスが実際の実装を定義せずに実装すべきプロパティとメソッドを指定することです。このようにすると、関連するオブジェクトのグループで使用するインターフェイスが統一されます。後でクラスを追加しても、インターフェイスは変化しません。
グラフを実装するインターフェイス クラス
この例では、特化したグラフを表すために使用するクラスのインターフェイスを作成します。このインターフェイスは、サブクラスで実装する必要のあるプロパティとメソッドを定義する抽象クラスです。
ただし、これらのコンポーネントをどのように実装するかは指定しません。このため、統一のインターフェイスを使用しても、特化したサブクラスごとに異なる機能を実装できる柔軟性が提供されます。
この例では、名前空間フォルダーに次のようなインターフェイス、派生したサブクラス、ユーティリティ関数が含まれます。
+graphics/GraphInterface.m % abstract interface class +graphics/LineGraph.m % concrete subclass
インターフェイスのプロパティとメソッド
GraphInterface クラスは次のプロパティを指定します。これらのプロパティは、サブクラスで定義しなければなりません。
Primitive— 特化したグラフの実装に使用されるグラフィックス オブジェクトのハンドル。クラスのユーザーは、これらのオブジェクトに直接アクセスする必要がないので、このプロパティのSetAccess属性とGetAccess属性はprotectedです。AxesHandle— グラフに使用する axes ハンドル。特化したgraphオブジェクトでは、axes オブジェクトのプロパティを設定できます。このプロパティにはprotectedSetAccessとGetAccessがあります。Data—GraphInterfaceクラスのすべてのサブクラスはデータを保存しなければなりません。データの種類が異なるので、各サブクラスでデータのストレージ方法を定義します。サブクラスのユーザーは、このプロパティがパブリックのアクセス権をもつようにデータ値を変更できます。
GraphInterface クラスは、サブクラスで実装しなければならない 3 つの抽象メソッドの名前を指定します。また、GraphInterface クラスのコメントには、各サブクラスのコンストラクターが、プロットするデータと、すべてのクラス プロパティの名前と値のペアを受け入れなければならないということが示唆されています。
サブクラス コンストラクター — データと、プロパティ/値のペアを受け入れ、オブジェクトを返します。
draw— サブクラスが実装するグラフのタイプに従って、基本のレンダリングを作成し、データをグラフ表示するために使用します。zoom— Axes のCameraViewAngleプロパティを変更することによる zoom メソッドの実装。このインターフェイスは、サブクラス間の整合のために関数camzoomを使用するように表示します。addButtons静的メソッドで作成されたズーム ボタンは、このメソッドをコールバックとして使用します。updateGraph—Dataプロパティが変更されるたびに、プロットされるデータを更新するためにset.Dataメソッドによって呼び出されるメソッド。
インターフェイス ガイド クラスの設計
GraphInterface 抽象クラスから派生するクラスの名前空間は、以下の動作を実装します。
プロットをレンダリングせずに特化した
GraphInterfaceオブジェクト (サブクラス オブジェクト) のインスタンスを作成する特化した
GraphInterfaceオブジェクトを作成するときに、オブジェクトのプロパティをまったく指定しないか、任意のプロパティを指定する現在表示されたプロットを自動的に更新するオブジェクト プロパティを変更する
特化した
GraphInterfaceオブジェクトのそれぞれで、必要に応じて追加のプロパティを実装可能にし、クラスのユーザーがこれらの特性を制御できるようにする
インターフェイスの定義
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
GraphInterface クラスは、プロパティの set メソッド (set.Data) を実装し、Data プロパティに対する変更をモニターします。代わりの方法として、Data プロパティを Abstract と定義することで、サブクラスは、このプロパティに set アクセス メソッドを実装するかどうかを決めることができます。GraphInterface クラスで抽象メソッド (各サブクラスで実装しなければならない updateGraph メソッド) を呼び出す set アクセス メソッドを定義します。GraphInterface インターフェイスによりクラスの名前空間全体に特定のデザインが組み込まれますが、自由度が制限されることはありません。
すべてのサブクラスで使用できるメソッド
addButtons メソッドによって、各サブクラスで実装しなければならない zoom メソッドにプッシュ ボタンを追加できます。通常の関数の代わりにメソッドを使用すると、addButtons で、クラスの保護されたデータ (axes ハンドル) にアクセスできるようになります。オブジェクトの 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
具象クラスの派生 — LineGraph
この例では、簡単な線グラフを表示するために使用するサブクラスを 1 つだけ定義します。このサブクラスは、GraphInterface から派生しますが、抽象メソッド draw、zoom、updateGraph、およびサブクラス自身のコンストラクターを実装します。基底クラス (GraphInterface) とサブクラスはすべて名前空間 (graphics) に含めます。この名前空間は、クラス名を参照するときに使用しなければなりません。
classdef LineGraph < graphics.GraphInterfaceプロパティの追加
LineGraph クラスは、GraphInterface クラスで定義されるインターフェイスを実装して 2 つのプロパティ (LineColor と LineType) を追加します。このクラスは、各プロパティの初期値を定義します。このため、コンストラクターでのプロパティ値の指定はオプションになります。データがなくても LineGraph オブジェクトを作成できますが、このオブジェクトからグラフを作成することはできません。
properties
LineColor = [0 0 0];
LineType = '-';
endLineGraph コンストラクター
コンストラクターは、x 座標および y 座標のデータをもつ struct と、プロパティの名前と値のペアを受け入れます。
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
draw メソッドの実装
LineGraph draw メソッドは、プロパティ値を使用して line オブジェクトを作成します。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
zoom メソッドの実装
LineGraph の zoom メソッドは、GraphInterface クラスにあるコメントに従って、関数 camzoom を使用します。関数 camzoom は、ズームのための便利なインターフェイスを提供し、addButtons メソッドによって作成されるプッシュ ボタンと共に正しく動作します。
プロパティの set メソッドの定義
プロパティの set メソッドは、コンストラクターのプロパティ値が初めて変更されたときに、自動的にコードが実行されるようにする便利な方法の 1 つです(プロパティの get メソッドおよび set メソッドを参照)。linegraph クラスは、プロパティ値が変更されるたびに set メソッドを使用して、始めの line データを更新します。プロットは、再描画されます。プロパティの set メソッドを使用すると、draw メソッドを呼び出さなくてもデータのプロットをすばやく更新できます。一方、draw メソッドは、現在のプロパティの値に合わせてすべての値をリセットして、プロットを更新します。
LineColor、LineType および Data の 3 つのプロパティで set メソッドを使用します。LineColor と LineType は、LineGraph クラスによって追加されるプロパティで、このクラスで使用する基本の line に固有のものです。その他のサブクラスでは、機能に特有の別のプロパティ (たとえば、FaceColor) を定義できます。
GraphInterface クラスは、Data プロパティの set メソッドを実装します。しかし、GraphInterface クラスの各サブクラスが updateGraph と呼ばれるメソッドを定義することが必要になります。このメソッドは、使用する特定の基本となる描画のプロット データを更新します。
LineGraph クラス
以下は 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 クラスの使用
LineGraph クラスは、graph 基底クラスが指定する簡単な API を定義し、特化したグラフを実装します。
d.x = 1:10; d.y = rand(10,1); lg = graphics.LineGraph(d,'LineColor','b','LineType',':'); lg.draw; lg.addButtons;
[ズーム アウト] ボタンをクリックすると、ボタンのコールバックによる zoom メソッドを表示します。

プロパティを変更すると、グラフが更新されます。
d.y = rand(10,1); lg.Data = d; lg.LineColor = [0.9,0.1,0.6];
ここで、[ズーム アウト] をクリックして新しい結果を参照します。
