Main Content

クラスの互換性の保持

プロパティの名称変更

プロパティの名前を変更したうえで、元のプロパティを参照する既存のコードでエラーが発生しないようにする場合を考えます。たとえば、OfficeNumber というパブリック プロパティを Location という名前に変更します。以下は元のクラス定義です。

classdef EmployeeList
   properties
      Name
      Email
      OfficeNumber % Rename as Location
   end
end

非表示の依存プロパティを使用することにより、望ましい結果が得られます。

  • クラス定義で、OfficeNumber プロパティの属性を Dependent および Hidden に設定します。

  • Location プロパティの値を設定する、OfficeNumber のプロパティ set メソッドを作成します。

  • Location プロパティの値を返す、OfficeNumber のプロパティ get メソッドを作成します。

OfficeNumber プロパティは非表示になっていますが、既存のコードは引き続きこのプロパティにアクセスできます。Hidden 属性はアクセスに影響しません。

OfficeNumber は依存関係にあるため、新しいプロパティの追加に必要な余剰のストレージはありません。MATLAB® は依存プロパティの保持や保存は行いません。

以下は、更新されたクラス定義です。

classdef EmployeeList
   properties
      Name
      Email
      Location
   end
   properties (Dependent, Hidden)
      OfficeNumber
   end
   methods
      function obj = set.OfficeNumber(obj,val)
         obj.Location = val;
      end
      function val = get.OfficeNumber(obj)
         val = obj.Location;    
      end
   end
end

EmployeeList オブジェクトの保存と読み込み

新しいクラス バージョンがある場合でも、EmployeeList クラスの古いインスタンスを読み込むことができます。OfficeNumber プロパティを参照するコードは引き続き機能します。

上位互換性と下位互換性

古いバージョンの EmployeeList クラスがまだ残っているシステムに、新しい EmployeeList オブジェクトを読み込めるようにする場合を考えます。新旧のバージョンで互換性を実現するには、次のようにします。

  • OfficeNumber プロパティを、Hidden として定義しますが、Dependent にはしません。

  • Location プロパティを Dependent として定義します。

このバージョンの EmployeeList クラスでは、OfficeNumber プロパティによって Location プロパティの使用する値が保存されます。オブジェクトを読み込むと元からある 3 つのプロパティ (NameEmailOfficeNumber) の値が代入されますが、新しい Location プロパティには値が代入されません。古いクラス定義に Location プロパティがなくても問題ありません。

classdef EmployeeList
   properties
      Name
      Email
   end
   properties (Dependent)
      Location
   end
   properties (Hidden)
      OfficeNumber
   end
   methods
      function obj = set.Location(obj,val)
         obj.OfficeNumber = val;
      end
      function val = get.Location(obj)
         val = obj.OfficeNumber;
      end
   end
end

読み込み時のプロパティ更新

プロパティ値の形式または型が変わるような変更をクラスに加えるとします。以前に保存されたそのクラスのオブジェクトは、読み込みに際して、適切なプロパティ値をもつよう更新しなければなりません。

AccountID プロパティをもつクラスについて考えます。すべての口座番号を 8 桁の数値から 12 要素の文字配列に移行させなければならないとします。

loadobj メソッドを実装することでこの変更に対応できます。

loadobj メソッドには以下の機能があります。

  • テストを行い、関数 loadstruct とオブジェクトのいずれを渡したかを判定する。load でエラーが発生した場合、すべての loadobj メソッドは struct とオブジェクトの両方を扱わなければなりません。

  • テストを行い、AccountID 番号に 8 桁の数値が含まれているかどうかを判定する。その場合は、padAccID メソッドを呼び出して 12 要素の文字配列に変更します。

AccountID プロパティを更新した後、loadobj は MATLAB がワークスペースに読み込む MyAccount オブジェクトを返します。

classdef MyAccount
   properties
      AccountID
   end
   methods
      function obj = padAccID(obj)
         ac = obj.AccountID;
         acstr = num2str(ac);
         if length(acstr) < 12
            obj.AccountID = [acstr,repmat('0',1,12-length(acstr))];
         end
      end
   end
   methods (Static)
      function obj = loadobj(a)
         if isstruct(a)
            obj = MyAccount;
            obj.AccountID = a.AccountID;
            obj = padAccID(obj);
         elseif isa(a,'MyAccount')
            obj = padAccID(a);
         end
      end
   end
end

saveobj メソッドを実装する必要はありません。loadobj は、保存された旧オブジェクトを読み込み時に確実に最新にするためにのみ使用されています。

クラスの互換バージョンの維持

PhoneBookEntry クラスは、新バージョンのクラスとの互換性を保つために複数の手法を組み合わせて使用します。

電話帳のエントリを表すクラスを定義するとします。PhoneBookEntry クラスは 3 つのプロパティ (NameAddress および PhoneNumber) を定義します。

classdef PhoneBookEntry
   properties
      Name
      Address
      PhoneNumber
   end
end

しかし、将来のリリースで、このクラスにはさらにプロパティが追加されます。柔軟性をもたせるため、PhoneBookEntry はその saveobj メソッドを使用して struct にプロパティ データを保存します。

methods
   function s = saveobj(obj)
      s.Name = obj.Name;
      s.Address = obj.Address;
      s.PhoneNumber = obj.PhoneNumber;
   end
end

loadobj メソッドは PhoneBookEntry オブジェクトを作成し、これがワークスペースに読み込まれます。

methods (Static)
   function obj = loadobj(s)
      if isstruct(s)
         newObj = PhoneBookEntry;
         newObj.Name = s.Name;
         newObj.Address = s.Address;
         newObj.PhoneNumber = s.PhoneNumber;
         obj = newObj;
      else
         obj = s;
      end
   end
end

バージョン 2 の PhoneBookEntry クラス

バージョン 2 の PhoneBookEntry クラスでは、Address プロパティを StreetAddressCityState および ZipCode の各プロパティに分割します。

こうした変更により、バージョン 2 のオブジェクトを以前のリリースに読み込むことができなくなります。しかし、バージョン 2 ではいくつかの手法により互換性が実現されています。

  • Address プロパティ (バージョン 1 で使用) をプライベートな SetAccess をもつ Dependent プロパティとして保持します。

  • バージョン 2 の Address プロパティと互換性のある char ベクトルを作成するために、Address プロパティの get メソッド (get.Address) を定義します。

  • saveobj メソッドは、以前のバージョンと互換性のある struct にオブジェクト データを割り当てるために、get.Address メソッドを呼び出します。struct は、新規の StreetAddressCityStateZipCode プロパティにおいて、データから作成された Address フィールドのみをもち続けます。

  • loadobj メソッドが Address プロパティを設定すると、これはプロパティの set メソッド (set.Address) を呼び出します。このメソッドは、StreetAddressCityStateZipCode の各プロパティで必要とされる部分文字列を抽出します。

  • Transient (保存されない) プロパティの SaveInOldFormat により、バージョン 2 のオブジェクトを struct とオブジェクトのいずれとして保存するかを指定できます。

classdef PhoneBookEntry
   properties
      Name
      StreetAddress
      City
      State
      ZipCode
      PhoneNumber
   end
   properties (Constant)
      Sep = ', '
   end
   properties (Dependent, SetAccess=private)
      Address
   end
   properties (Transient)
      SaveInOldFormat = false;
   end
   methods (Static)
      function obj = loadobj(s)
         if isstruct(s)
            obj = PhoneBookEntry;
            obj.Name = s.Name;
            obj.Address = s.Address;
            obj.PhoneNumber = s.PhoneNumber;
         else
            obj = s;
         end
      end
   end
   methods
      function address = get.Address(obj)
         address = [obj.StreetAddress,obj.Sep,obj.City,obj.Sep,...
            obj.State,obj.Sep,obj.ZipCode];
      end
      function obj = set.Address(obj,address)
         addressItems = regexp(address,obj.Sep,'split');
         if length(addressItems) == 4
            obj.StreetAddress = addressItems{1};
            obj.City = addressItems{2};
            obj.State = addressItems{3};
            obj.ZipCode = addressItems{4};
         else
            error('PhoneBookEntry:InvalidAddressFormat', ...
               'Invalid address format.');
         end
      end
      function s = saveobj(obj)
         if obj.SaveInOldFormat
            s.Name = obj.Name;
            s.Address = obj.Address;
            s.PhoneNumber = obj.PhoneNumber;
         end
      end
   end
end

関連するトピック