Maintaining Class Compatibility

Versions of a Phone Book Application Program

This section shows you how to use saveobj and loadobj methods to maintain compatibility among subsequent releases of an application program. Suppose you have created a program that implements a phone book application, which can be used to keep track of information about various people and companies.

One of the key elements of this program is that it uses a data structure to contain the information for each phone book entry. You save these data structures in MAT-files. This example shows ways to maintain the compatibility of subsequent versions of the data structures as you implement new versions of the program.

When the phone book application program loads a particular phone book entry by reading a variable from a Mat-file, it must ensure that the loaded data can be used by the current version of the application.

Version 1 — Stores Data in struct

Suppose in Version 1 of the phone book application program, you used an ordinary MATLAB® struct to save phone book entries in the fields: Name, Address, and PhoneNumber. Your phone book application program saves these variables in a MAT-file. For example, here is a typical entry:

V1.Name = 'The MathWorks, Inc.';
V1.Address = '3 Apple Hill Drive, Natick, MA, 01760';
V1.PhoneNumber = '5086477000';

Version 2 — Maps struct Fields to Object Properties

With Version 2 of the phone book program, you change from a struct to a class having public properties with the same names as the fields in the struct. You want to save the new PhoneBookEntry objects and you want to load the old struct without causing any errors. To maintain this compatibility, the PhoneBookEntry class implements loadobj and saveobj methods:

classdef PhoneBookEntry
   properties
      Name
      Address
      PhoneNumber
   end
   methods (Static)
      function obj = loadobj(obj)
         if isstruct(obj)
            % Call default constructor
            newObj = PhoneBookEntry;
            % Assign property values from struct
            newObj.Name = obj.Name;
            newObj.Address = obj.Address;
            newObj.PhoneNumber = obj.PhoneNumber;
            obj = newObj;
         end
      end
   end
   methods
      function obj = saveobj(obj)
         s.Name = obj.Name;
         s.Address = obj.Address;
         s.PhoneNumber = obj.PhoneNumber;
         obj = s;
      end
   end
end

saveobj saves the object data in a struct that uses property names for field names. This struct is compatible with Version 1 of the product. When the struct is loaded into Version 2 of the phone book application program, the static loadobj method converts the struct to a PhoneBookEntry object. For example, given the previously defined struct V1:

V1 = 

           Name: 'MathWorks, Inc.'
        Address: '3 Apple Hill Drive, Natick, MA, 01760'
    PhoneNumber: '5086477000'

The application program can use the loadobj static method to convert this Version 1 struct to a Version 2 object:

V2 = PhoneBookEntry.loadobj(V1)

V2 = 

  PhoneBookEntry with properties:

           Name: 'MathWorks, Inc.'
        Address: '3 Apple Hill Drive, Natick, MA, 01760'
    PhoneNumber: '5086477000'

If a Version 2 PhoneBookEntry object is loaded, load automatically calls the object's loadobj method, which converts the struct to an object compatible with Version 2 of the phone book application program.

Version 3 — Adds More Properties to Class

In Version 3, you change the PhoneBookEntry class by splitting the Address property into StreetAddress, City, State, and ZipCode properties. With this version, you cannot load a Version 3 PhoneBookEntry object in previous releases by default. However, the saveobj method provides an option to save Version 3 objects as structs that you can load in Version 2. The loadobj method enables you to load both Version 3 objects and Version 2 structs.

Here is the new version of the PhoneBookEntry class.

classdef PhoneBookEntry
   properties
      Name
      StreetAddress
      City
      State
      ZipCode
      PhoneNumber
   end
   properties (Constant)
      Sep = ', ';
   end
   properties (Dependent, SetAccess=private)
      Address
   end
   properties (Transient)
      SaveInOldFormat = 0;
   end
   methods (Static)
      function obj = loadobj(obj)
         if isstruct(obj)
            % Call default constructor
            newObj = PhoneBookEntry;
            % Assign property values from struct
            newObj.Name = obj.Name;
            newObj.Address = obj.Address;
            newObj.PhoneNumber = obj.PhoneNumber;
            obj = newObj;
         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 obj = saveobj(obj)
       % If set to true, save as a struct
         if obj.SaveInOldFormat 
            s.Name = obj.Name;
            s.Address = obj.Address;
            s.PhoneNumber = obj.PhoneNumber;
            obj = s;
         end
   end
end

To maintain compatibility among all versions, Version 3 of the PhoneBookEntry class applies the following techniques:

  • Preserve the Address property (which is used in Version 2) as a Dependent property with private SetAccess.

  • Define an Address property get method (get.Address) to build a string that is compatible with the Version 2 Address property.

  • The get.Address method is invoked from the saveobj method to assign the object data to a struct that is compatible with previous versions. The struct continues to have only an Address field built from the data in the new StreetAddress, City, State, and ZipCode properties.

  • As the loadobj method sets the object's Address property, it invokes the property set method (set.Address), which extracts the substrings required by the StreetAddress, City, State, and ZipCode properties.

  • The Transient (not saved) property SaveInOldFormat enables you to specify whether to save the Version 3 object as a struct or an object.

See Property Access Methods for more on property set and get methods.

Was this topic helpful?