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 to Dependent
and Hidden
.
Create a property set method for OfficeNumber
that sets the value of the Location
property.
Create a property get method for OfficeNumber
that returns the value of the Location
location 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
EmployeeList
ObjectsYou 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.
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 as Hidden
, but not Dependent
.
Define the Location
property as Dependent
.
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
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 a struct
or object. All loadobj
methods must handle both struct
and object when there is an error in load
.
Tests to determine if the AccountID
number contains eight digits. If so, change it to a 12-element character array by calling the paddAccID
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.
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
PhoneBookEntry
ClassIn 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 a Dependent
property with private SetAccess
.
Define an Address
property get method (get.Address
) to build a char
vector that is compatible with the version 2 Address
property.
The saveobj
method invokes the get.Address
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.
When the loadobj
method sets the 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 2 object as a struct
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