Maintain Class Compatibility
Rename Property
Suppose that you want to rename a property, but do not want to cause errors in existing code that refer to the original property. For example, rename a public property called OfficeNumber
to Location
. Here is the original class definition:
classdef EmployeeList properties Name Email OfficeNumber % Rename as Location end end
Use of a hidden dependent property can achieve the desired results.
In the class definition, set the
OfficeNumber
property attributes toDependent
andHidden
.Create a property set method for
OfficeNumber
that sets the value of theLocation
property.Create a property get method for
OfficeNumber
that returns the value of theLocation
property.
While the OfficeNumber
property is hidden, existing code can continue to access this property. The Hidden
attribute does not affect access.
Because OfficeNumber
is dependent, there is no redundancy in storage required by adding the new property. MATLAB® does not store or save dependent properties.
Here is the updated class definition.
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
Saving and Loading EmployeeList
Objects
You can load old instances of the EmployeeList
class in the presence of the new class version. Code that refers to the OfficeNumber
property continues to work.
Forward and Backward Compatibility
Suppose that you want to be able to load new EmployeeList
objects into systems that still have the old version of the EmployeeList
class. To achieve compatibility with old and new versions:
Define the
OfficeNumber
property asHidden
, but notDependent
.Define the
Location
property asDependent
.
In this version of the EmployeeList
class, the OfficeNumber
property saves the value used by the Location
property. Loading an object assigns values of the three original properties (Name
, Email
, and OfficeNumber
), but does not assign a value to the new Location
property. The lack of the Location
property in the old class definition is not a problem.
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
Update Property When Loading
Suppose that you modify a class so that a property value changes in its form or type. Previously saved objects of the class must be updated when loaded to have a conforming property value.
Consider a class that has an AccountID
property. Suppose that all account numbers must migrate from eight-digit numeric values to 12-element character arrays.
You can accommodate this change by implementing a loadobj
method.
The loadobj
method:
Tests to determine if the
load
function passed astruct
or object. Allloadobj
methods must handle bothstruct
and object when there is an error inload
.Tests to determine if the
AccountID
number contains eight digits. If so, change it to a 12-element character array by calling thepadAccID
method.
After updating the AccountID
property, loadobj
returns a MyAccount
object that MATLAB loads into the workspace.
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
You do not need to implement a saveobj
method. You are using loadobj
only to ensure that older saved objects are brought up to date while loading.
Maintaining Compatible Versions of a Class
The PhoneBookEntry
class uses a combination of techniques to maintain compatibility with new versions of the class.
Suppose that you define a class to represent an entry in a phone book. The PhoneBookEntry
class defines three properties: Name
, Address
, and PhoneNumber
.
classdef PhoneBookEntry properties Name Address PhoneNumber end end
However, in future releases, the class adds more properties. To provide flexibility, PhoneBookEntry
saves property data in a struct
using its saveobj
method.
methods function s = saveobj(obj) s.Name = obj.Name; s.Address = obj.Address; s.PhoneNumber = obj.PhoneNumber; end end
The loadobj
method creates the PhoneBookEntry
object, which is then loaded into the workspace.
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
Version 2 of the PhoneBookEntry
Class
In version 2 of the PhoneBookEntry
class, you split the Address
property into StreetAddress
, City
, State
, and ZipCode
properties.
With these changes, you could not load a version 2 object in a previous release. However, version 2 employs several techniques to enable compatibility:
Preserve the
Address
property (which is used in version 1) as aDependent
property with privateSetAccess
.Define an
Address
property get method (get.Address
) to build achar
vector that is compatible with the version 2Address
property.The
saveobj
method invokes theget.Address
method to assign the object data to astruct
that is compatible with previous versions. Thestruct
continues to have only anAddress
field built from the data in the newStreetAddress
,City
,State
, andZipCode
properties.When the
loadobj
method sets theAddress
property, it invokes the property set method (set.Address
), which extracts the substrings required by theStreetAddress
,City
,State
, andZipCode
properties.The
Transient
(not saved) propertySaveInOldFormat
enables you to specify whether to save the version 2 object as astruct
or an object.
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