1. Trang chủ
  2. » Kỹ Thuật - Công Nghệ

CRC.Press A Guide to MATLAB Object Oriented Programming May.2007 Episode 2 Part 3 doc

20 194 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 20
Dung lượng 890,29 KB

Nội dung

214 A Guide to MATLAB Object-Oriented Programming 28 case 'Color' 29 if isempty(this) 30 varargout = {}; 31 else 32 varargout = cell(size(this)); % trick next function's nargout 33 % either index(2:end) or varargin{1} should be empty 34 [do_sub_indexing, do_assignin, this, varargout{:}] = 35 Color_helper('get', this, [index(2:end) varargin{:}]); 36 end 37 case 'LineWidth' 38 if isempty(this) 39 varargout = {}; 40 else 41 varargout = {this.mLineWidth}; 42 end 43 case 'LineHandle' 44 if isempty(this) 45 varargout = {}; 46 else 47 varargout = {this.mLineHandle}; 48 end 49 otherwise 50 found = false; % didn't find it in the public section 51 end 52 53 % concealed member variables, not strictly public 54 if ~found && called_by_name 55 found = true; 56 switch index(1).subs 57 case 'mDisplayFunc' % class-wizard reserved field 58 if isempty(this) 59 varargout = {}; 60 else 61 varargout = {this.mDisplayFunc}; 62 end 63 otherwise 64 found = false; % didn't find it in the concealed section 65 end 66 end 67 68 % parent forwarding block 69 if ~found 70 if called_by_name 71 forward_index = index(1).subs; C911X_C016.fm Page 214 Friday, March 30, 2007 11:42 AM General Assignment and Mutator Helper Functions 215 72 else 73 forward_index = index; 74 end 75 76 if nargout == 0 77 varargout = cell(size(this)); 78 else 79 varargout = cell(1, nargout); 80 end 81 82 for parent_name = parent_list' % loop over parent cellstr 83 try 84 parent = [this.(parent_name{1})]; 85 [varargout{:}] = get(parent, forward_index, varargin{:}); 86 found = true; % catch will assign false if not found 87 do_sub_indexing = false; % assume parent did all sub- indexing 88 break; % can only get here if field is found 89 catch 90 found = false; 91 err = lasterror; 92 switch err.identifier 93 case 'MATLAB:nonExistentField' 94 % NOP 95 otherwise 96 rethrow(err); 97 end 98 end 99 end 100 if do_assignin 101 parent = num2cell(parent); 102 [this.(parent_name{1})] = deal(parent{:}); 103 end 104 end 105 106 % error checking 107 if ~found 108 error('MATLAB:nonExistentField', 109 'Reference to non-existent field identifier %s', 110 index(1).subs); 111 end 112 113 % nargout adjustment 114 if length(varargout) > 1 & nargout <= 1 115 if iscellstr(varargout) || any([cellfun('isempty', varargout)]) C911X_C016.fm Page 215 Friday, March 30, 2007 11:42 AM 216 A Guide to MATLAB Object-Oriented Programming The first changes occur in lines 3 and 4. The local variables do_sub_indexing and do_assignin guard code blocks near the end of this now standard version of get. Helper functions return values for these two variables, but we never know in advance whether a direct- link public variable or a non-direct-link variable is being accessed. Lines 3 and 4 assign initial values compatible with direct-link access. During non-direct-link access, the helper function assigns values to these variables. 116 varargout = {varargout}; 117 else 118 try 119 varargout = {[varargout{:}]}; 120 catch 121 varargout = {varargout}; 122 end 123 end 124 end 125 126 % special syntax block, see book section 3 127 if do_assignin 128 var_name = inputname(1); 129 if isempty(var_name) 130 warning('get with assignment is only for non-indexed objects'); 131 else 132 assignin('caller', var_name, this); 133 caller = evalin('caller', 'mfilename'); 134 if ~isempty(strmatch(caller, {'subsref' 'subsasgn' 'get' 'set'})) 135 assignin('caller', 'do_assignin', true); 136 end 137 end 138 end 139 140 % deep indexing block 141 if do_sub_indexing 142 index = [index(2:end) varargin{:}]; 143 if length(index) > 0 144 if length(this) == 1 145 varargout = {subsref([varargout{:}], index)}; 146 147 else 148 [err_id, er_msg] = array_reference_error(index(1).type); 149 end 150 end 151 end C911X_C016.fm Page 216 Friday, March 30, 2007 11:42 AM General Assignment and Mutator Helper Functions 217 The next change brings us into the public member variable section. The case for ‘Color’, lines 28–36, uses a helper function. As before, line 28 identifies the ‘Color’ case, and when the object is empty, line 30 returns an empty varargout. When the object is not empty, line 32 prepares for the helper call by preallocating varargout. Lines 34–35 call the helper. There are three input arguments and three plus length(varargout) outputs. The first input, ‘get’, tells the helper to perform an access operation. The second input, this, is the source of the access. The third input is a concatenation of index(2:end) and varargin{:}. The values in index and varargin depend on the path leading up to the helper call. If the path began with dot-reference syntax, index(2:end) will contain additional indices converted from operator notation and varargin will be empty. If the path began with a call to get, index(2:end) will be empty but varargin might include an additional substruct index. The concatenation assembles the entire index and passes it into the helper. One important thing to notice is the fact that there is no limit imposed on the length of the index passed into the helper. Ordinarily MATLAB places limits on indexing into nonscalar variables. In most situations, the group-of-eight implementation also places limits on indexing. The length of the index passed into the helper is an exception because the helper is responsible for these decisions. When the helper accepts this responsibility it returns a value of false in do_sub_indexing. The helper returns values for do_sub_indexing, do_assignin, this, and varar- gout. Allowing the helper to index into the dot-referenced value and return a do_sub_indexing value of false means that values returned from the helper might be fully indexed. This has implications for subsref because, currently, subsref will incorrectly reindex the values. To fix this problem, indexing code is moved out of subsref and into lines 140–151. The code previously shown in Code Listing 98 will no longer exist in the standard version of subsref. Instead, all standard versions of get will include the ability to perform deeper indexing. It should come as no surprise that the do_sub_indexing flag guards this ability. The helper also returns a value for do_assignin. Do_assignin is used as a guard value for lines 127–138. These lines implement some special syntax that will be described in Part 3. Until we take up that discussion, the value returned by the helper will always be false. That way, until we discuss the pros and cons of returning a true value, we will skip over 127–138. You might also notice other do_assignin-related additions. These additions are also discussed in Part 3. The final addition occurs on line 87 inside the parent-forwarding section. When the get forward in line 85 executes without error, line 86 sets found equal to true and line 87 sets do_sub_indexing to false. Now that we have moved the indexing code into get, the parent’s version will have already performed any necessary indexing and we don’t want to reindex the values. Of course, this also means that all of our classes need to be updated with the new group- of-eight functions described in this chapter. 16.1.2.3 Final Template for set.m Case code for set is shown in Code Listing 101. Code Listing 101, Final Version of set.m Implemented for cLineStyle 1 function varargout = set(this, index, varargin) 2 3 do_assignin = false; % special variable, see book section 3 4 5 if nargin < 3 % one or two arguments, display info and return C911X_C016.fm Page 217 Friday, March 30, 2007 11:42 AM 218 A Guide to MATLAB Object-Oriented Programming 6 possible = fieldnames(this, '-possible'); 7 possible_struct = struct(possible{:}); 8 if nargout == 0 9 if nargin == 1 10 disp(possible_struct); 11 else 12 try 13 temp_struct.(index) = possible_struct.(index); 14 disp(temp_struct); 15 catch 16 warning(['??? Reference to non-existent field ' 17 index '.']); 18 end 19 end 20 else 21 varargout = cell(1,max([1, nargout])); 22 varargout{1} = possible_struct; 23 end 24 return; 25 end 26 27 called_by_name = ischar(index); 28 29 % the set switch below needs a substruct 30 if called_by_name 31 index = substruct('.', index); 32 end 33 34 % public-member-variable section 35 found = true; % otherwise-case will flip to false 36 switch index(1).subs 37 case 'Color' 38 [do_sub_indexing, do_assignin, this] = 39 Color_helper('set', this, index(2:end), varargin{:}); 40 case 'LineWidth' 41 [do_sub_indexing, do_assignin, this] = 42 LineWidth_helper('set', this, index(2:end), varargin{:}); 43 case 'LineHandle' 44 if length(index) > 1 45 if length(this) == 1 46 this.mLineHandle = 47 subsasgn(this.mLineHandle, 48 index(2:end), varargin{:}); 49 else 50 [err_id, err_msg] = array_reference_error(index(1) .type); C911X_C016.fm Page 218 Friday, March 30, 2007 11:42 AM General Assignment and Mutator Helper Functions 219 51 error(err_id, err_msg); 52 end 53 else 54 [this.mLineHandle] = deal(varargin{:}); 55 end 56 otherwise 57 found = false; 58 end 59 60 % concealed member variables, not strictly public 61 if ~found && called_by_name 62 found = true; 63 switch index(1).subs 64 case 'mDisplayFunc' 65 if length(index) > 1 66 this.mDisplayFunc = 67 subsasgn(this.mDisplayFunc, 68 index(2:end), varargin{:}); 69 else 70 [this.mDisplayFunc] = deal(varargin{:}); 71 end 72 otherwise 73 found = false; % didn't find it in the special section 74 end 75 end 76 77 % parent forwarding block 78 if ~found 79 if called_by_name 80 forward_index = index(1).subs; 81 else 82 forward_index = index; 83 end 84 85 for parent_name = parent_list' % loop over parent cellstr 86 try 87 parent = set([this.(parent_name{1})], forward_index, varargin{:}); 88 parent = num2cell(parent); 89 [this.(parent_name{1})] = deal(parent{:}); 90 found = true; % catch will assign false if not found 91 break; % can only get here if field is found 92 catch 93 found = false; 94 err = lasterror; 95 switch err.identifier 96 case 'MATLAB:nonExistentField' C911X_C016.fm Page 219 Friday, March 30, 2007 11:42 AM 220 A Guide to MATLAB Object-Oriented Programming The first change to set occurs in line 3. The logical variable do_assignin guards entry into the block of code added in lines 110–122. Behavior related to do_assignin will be described in Part 3. Until then, do_assignin should be false and line 3 assigns false as the initial value. The next change brings us into the public member variable section. The case for ‘Color’, lines 37–39, uses a helper function. Line 37 identifies the ‘Color’ case, and lines 38–39 call the helper. This time the first argument is ‘set’ because we want to execute the mutator. The remaining three arguments are the object, the additional indices, and the assignment values. The helper returns values for do_sub_indexing, do_assignin, and the mutated object. In this case, do_sub_indexing is a dummy variable because it is never used by set. The case for ‘LineWidth’ is interesting because get uses direct-link code but set uses a helper. This is typical because the standard organization moves input-value-checking code into the helper. The mutator needs to check the input values, but the accessor does not. Thus, the mutator uses a helper but the accessor does not. Finally, the case for LineHandle uses the standard direct- link syntax. 97 % NOP 98 otherwise 99 rethrow(err); 100 end 101 end 102 end 103 end 104 105 if ~found 106 error('MATLAB:nonExistentField', 107 '??? Reference to non-existent field ', 108 index(1).subs); 109 end 110 111 if do_assignin % set used in special way, see book section 3 112 var_name = inputname(1); 113 if isempty(var_name) 114 warning('MATLAB:invalidInputname', 115 'No assignment: set with assignment needs a non- indexed object'); 116 else 117 assignin('caller', var_name, this); 118 caller = evalin('caller', 'mfilename'); 119 if ~isempty(strmatch(caller, {'subsref' 'subsasgn' 'get' 'set'})) 120 assignin('caller', 'do_assignin', true); 121 end 122 end 123 end 124 125 varargout{1} = this; C911X_C016.fm Page 220 Friday, March 30, 2007 11:42 AM General Assignment and Mutator Helper Functions 221 16.1.2.4 Color Helper Function Code for one combined accessor–mutator helper function is shown in Code Listing 102. This particular helper is used for the public member variable color. Code in the listing should look familiar because most of the lines came directly from member functions in Chapter 15. Of course, the organization is different and there is a lot going on in this function. Code Listing 102, Final Version of cLineStyle’s Color_helper.m 1 function [do_sub_indexing, do_assignin, this, varargout] = 2 Color_helper(which, this, index, varargin) 3 4 switch which 5 6 case 'get' % ACCESSOR 7 do_sub_indexing = true; % true and get will index deeper 8 do_assignin = false; % typically false, see book section 3 9 rgb = hsv2rgb([this.mColorHsv]')'; % convert color format 10 varargout = num2cell(rgb, 1); % num2cell instead of mat2cell 11 12 case 'set' % MUTATOR 13 do_sub_indexing = false; % mutator must do deeper indexing 14 do_assignin = false; % typically false, see book section 3 15 varargout = {}; % mutator doesn't use varargout 16 if isempty(index) % only an initial dot-reference value 17 rgb = [varargin{:}]; % input values are rgb 18 else % deeper indexing 19 if length(this) == 1 20 rgb = subsasgn(get(this, 'Color'), index, varargin{:}); 21 else 22 [err_id, err_msg] = array_reference_error(index(1). type); 23 error(err_id, err_msg); 24 end 25 end 26 hsv = num2cell(rgb2hsv(rgb')', 1); % convert rgb to hsv 27 [this.mColorHsv] = deal(hsv{:}); % assign new hsv values 28 29 for k = 1:length(this(:)) 30 try 31 set(this(k).mLineHandle, 'Color', get(this(k), 'Color')); 32 end 33 end 34 C911X_C016.fm Page 221 Friday, March 30, 2007 11:42 AM 222 A Guide to MATLAB Object-Oriented Programming First notice the file is separated into two sections: accessor (lines 3–10) and mutator (lines 12–37). This is not necessarily required, but it is a convenient organization. Both sections assign values to do_sub_indexing, do_assignin, and varargout. The accessor code can allow get to finish deeper indexing by setting do_sub_indexing equal to true. That is what this helper does on line 7. The accessor code can also elect to perform deeper indexing by setting do_sub_indexing equal to false. The mutator code must always perform deeper indexing and will always set do_sub_indexing equal to false. The accessor code then converts private HSV values into RGB values on line 9. To populate the varargout cell array, line 10 converts the RGB array values into a cell array. The mutator code doesn’t return values via varargout, so it sets varargout to empty in line 15. Instead of using varargout, mutator code performs the mutation in place and returns the mutated object. When the variable name is the only index, line 17 copies input RGB values into a temporary variable. When there are additional indices, line 19 checks the size of the object array. If the array is scalar, line 20 uses subsasgn to assign the subset. If the array is nonscalar, lines 22–23 throw an error by calling array_reference_error. After populating the rgb temporary variable, line 26 converts the RGB values into HSV values and stores the HSV values in a cell array. Line 27 then deals the cell values into the correct locations. Finally, lines 29–33 loop over all the objects in the array and set their line colors to the newly assigned values. Just like before, using the handle-graphics set silently does nothing when the handle is empty. 16.1.2.5 The Other Classes and Member Functions Before cLineStyle can be used in our current collection of classes, we need to code LineWidth_helper. The implementation follows the same strategy used for Color_helper. The code is included in the Chapter 16 @cLineStyle/private directory. The mutator section includes index checking, value checking, and input size checking identical to Chapter 15’s set case. While not technically required, we should also be able to convert member functions for cShape, cStar, and cDiamond into this chapter’s newly established, group-of-eight format. The old class organization will work with the new version of cLineStyle because its public interface didn’t change. The problem with keeping the old class organization is one of consistency. A collection of classes is much easier to maintain if they all consistently conform to the same internal strategy. Affected group-of-eight member functions are get, set, subsref, and subsasgn. The new organization also uses helper functions for non-direct-link public variables. The previous implementations for cShape, cStar, and cDiamond were also reorganized to use helpers. Implementations of the various helper functions follow the same strategy laid out in this chapter. The newly organized class files can be found in the chapter_16 directory. You should look at these files and pay close attention to the helper functions in the private directories. 16.2 TEST DRIVE The code in this chapter represents reorganization with no new functionality. All of the commands from previous chapters should still work the same as they did before. We need to rerun some of our test commands to make sure our classes still behave the same. Some of the Chapter 15 35 otherwise 36 error('OOP:unsupportedOption', ['Unknown helper option: ' which]); 37 end C911X_C016.fm Page 222 Friday, March 30, 2007 11:42 AM General Assignment and Mutator Helper Functions 223 commands for cStar objects are repeated in Code Listing 103. The commands confirm that the helper-function interface is working correctly across our parent–child and primary-secondary hier- archies. The figure that results from the command in line 6 is shown in Figure 16.1. 16.3 SUMMARY The focus of this chapter was the organization of get and set. By changing the organization, we improved the modularity of the standard group of eight. To do this we considered two situations: direct-link variables and variables that use a helper function. Direct-link variables are easy to access and mutate because there is no data conversion or input checking. The code to access and mutate these variables is short and essentially the same every time. Public variables that use a helper include those that convert data from one representation to another and those that perform any sort if input check during mutation. FIGURE 16.1 cStar graphic after implementing helper-function syntax. Code Listing 103, Chapter 16 Test Drive Command Listing: The cStar Interface 1 >> cd '/oop_guide/chapter_16' 2 >> clear classes; fclose all; close all force; diary off; 3 >> star = [cStar cStar]; 4 >> star(2).ColorRgb = [1;0;0]; 5 >> star(1) = 1.5 * star(1); 6 >> star = draw(star); 7 >> star(1).Title = 'Shooting Star'; 8 >> star(1).LineWeight = 'bold'; 9 >> star(1) 10 ans = 11 Size: [2x1 double] 12 ColorRgb: [3x1 double] 13 Points: [2x6 double] 14 LineWeight: 'bold' 15 Title: 'Shooting Star' 2 1 0 –1 –2 10 Shooting Star –1–2 2 C911X_C016.fm Page 223 Friday, March 30, 2007 11:42 AM [...]...C911X_C016.fm Page 22 4 Friday, March 30 , 20 07 11: 42 AM 22 4 A Guide to MATLAB Object- Oriented Programming Moving accessor and mutator code outside of get and set also has another benefit It allows computer-aided-software-engineering (CASE) tools to manage the addition and removal of private, public, and concealed variables Without helper functions and their standard interface, every time a class changes, a lot... parent-constructor call doesn’t make its way into generated code exactly as displayed, but functionally the result is the same During file generation, data from these fields are written into the parent_list function Parent-class names are formatted as a cellstr and C911X_C017.fm Page 23 2 Friday, March 2, 20 07 8:50 AM 23 2 A Guide to MATLAB Object- Oriented Programming FIGURE 17.5 Class Wizard, Parents … dialog their... set of graphical components, and Class Wizard uses button groups For this reason Class Wizard will not run properly under versions of MATLAB below 7.0 There were also some changes to the object model; however, Class Wizard produces class code that is backward compatible with MATLAB version 6.5 22 5 C911X_C017.fm Page 22 6 Friday, March 2, 20 07 8:50 AM 22 6 A Guide to MATLAB Object- Oriented Programming The... because a variable name in the display is selected Selecting a blank line will insert an m in Private Variable Name, and the other fields will be blank A leading m is the suggested convention for naming private member variables The naming C911X_C017.fm Page 23 3 Friday, March 2, 20 07 8:50 AM Class Wizard 23 3 FIGURE 17.6 Class Wizard, Private Variables … dialog convention is optional, and any legal variable... data-entry fields are described by the following: Parent Class Name: holds the name of a class that will serve as a parent The dialog accepts more than one parent name, but each name-varargin pair is added separately varargin: holds a comma separated list of input arguments Enter the comma-separated list exactly as it should appear in a call to the constructor The values in the input list can be values,... subsasgn.m FIGURE 17.1 Dependency diagram for a simple class display.m C911X_C017.fm Page 22 7 Friday, March 2, 20 07 8:50 AM Class Wizard 22 7 Class Name Constructor Superior To Inferior To parent_list.m Parent Name(s) fieldnames.m Private Variables Public Variables struct.m get.m subsref.m set.m display.m subsasgn.m Concealed Variables FIGURE 17 .2 Dependency diagram with inheritance using Guide and MATLAB. .. private, concealed, and public variables and understand how they relate to one another This chapter describes data entry for the code-generation tool, but in reality, the full documentation for Class Wizard is the topic of this book * Guide is a standard MATLAB utility that can be used to efficiently create cross-platform graphical user interfaces MATLAB version 7.0 added button groups to the standard... because it gives variable names and comment headers a consistent form with shared comments across all members of the class The automation tool is called class_wizard.m The Class Wizard tool uses a graphical interface entirely developed using MATLAB s standard development tools Dialog screens and callback functions were developed using Guide* and MATLAB 7.0 In addition, all of the code in class_wizard.m... constructor The same name should also be used in the directory name, but the directory name is specified separately during file save operations The suggested naming convention for classes includes a lowercase “c” as the first character To help remind you of this convention, the field for Class Name initially C911X_C017.fm Page 22 8 Friday, March 2, 20 07 8:50 AM 22 8 A Guide to MATLAB Object- Oriented Programming FIGURE... corresponding input arguments are formatted into a cell array The format of the resulting code is identical to a hand-coded parent_list The Save Change button and two additional buttons located between the data-entry fields and the display list box cooperate to allow you to manage parent data If parent lines already exist in the display list box, you can click on a line and it will become active The line . ($Author: $) ($Revision: $) 23 % A Class Wizard v .3 assembled file generated: 20 -Dec -20 05 13 : 23 : 23 C911X_C017.fm Page 23 1 Friday, March 2, 20 07 8:50 AM 23 2 A Guide to MATLAB Object- Oriented Programming their. Star' 2 1 0 –1 2 10 Shooting Star –1 2 2 C911X_C016.fm Page 22 3 Friday, March 30 , 20 07 11: 42 AM 22 4 A Guide to MATLAB Object- Oriented Programming Moving accessor and mutator code outside of get and set also. To Inferior To Parent Name(s) Concealed Variables C911X_C017.fm Page 22 7 Friday, March 2, 20 07 8:50 AM 22 8 A Guide to MATLAB Object- Oriented Programming contains a lowercase c . The lowercase

Ngày đăng: 05/08/2014, 21:21