CRC.Press A Guide to MATLAB Object Oriented Programming May.2007 Episode 1 Part 7 potx

20 338 0
CRC.Press A Guide to MATLAB Object Oriented Programming May.2007 Episode 1 Part 7 potx

Đ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

C911X_C006.fm Page 94 Thursday, March 1, 2007 2:09 PM 94 A Guide to MATLAB Object-Oriented Programming 6.5 INDEPENDENT INVESTIGATIONS In the ‘-full’ case, use class to inspect and assign the field’s type What are you going to for object arrays? Modify display.m to take advantage of fieldnames C911X_C007.fm Page 95 Thursday, March 1, 2007 2:15 PM struct.m In the previous chapter, we patched a hole in MATLAB’s default encapsulation by tailoring fieldnames In this chapter, we patch another hole by tailoring struct As we have already seen, the built-in version of struct returns the names and values of private member variables In fact, struct’s default behavior represents a risky situation because clients can use it to gain access to private data We need to eliminate this possibility by developing a type-specific version of struct.m As a bonus, a standard function that returns an object’s public structure is broadly useful For example, look back at the scalar case of the tailored version of display The strategy of allowing MATLAB to perform most of the formatting requires a structure of public variables At that time, public structure generation was coded directly in line and we could not easily make use of it in developer view Further proliferation of in-line structure-generation code makes class extensions very tedious and error prone Consolidating structure generation into one function makes a lot of sense We can even take advantage of the tailored version of fieldnames so that even public names are not directly coded into struct 7.1 STRUCT While we could easily write a specific get function for this task (e.g., getPublicStructure), MATLAB already defines a suitable function The built-in version of struct already returns a structure associated with the object The built-in version will also operate on objects Unlike the help for fieldnames, help struct does not promise to return a structure of “public data fields.” The help files for struct describe a function that converts an object into its equivalent structure Here our idea of “equivalent structure” and MATLAB’s idea are definitely not the same In our world, the structure should contain public member variables; however, the built-in version of struct returns a structure made up of the private variables The fieldnames function was bad enough, but the struct function is even more despicable It returns both the names and the values of the private variables! While it is still true that MATLAB prevents changes to the private data, that does not prevent clients from using the values and even passing around the structures created from the object Here is yet another place where MATLAB seems very lax about preventing client access to private data We need to reinforce this area because the potential result of such permissiveness can be devastating If left unchecked, clients will use this back door to destroy most of the benefits of encapsulation Once a client ties code to the private structure returned by the default version of struct, later attempts to reorganize or improve the class will result in broken code and angry clients While it might indeed be their fault, it becomes our problem I have personally witnessed such chaos and can tell you it is no easy chore to clean it up Preventing it from happening in the first place is a much better plan Like always, if we don’t like what the built-in version gives us, we simply tailor the function to suit our purposes In this particular case, tailoring is not perfect because we can’t prevent clever or devious clients from using builtin to tie their code to an object’s private data A client can bypass all our carefully crafted member functions by using, for example, shape_struct = builtin(‘struct’, shape) When a client uses builtin in this way, shape_struct is not an object, but rather a structure With a structure, the client loses the ability to call member functions, but in return gains the ability 95 C911X_C007.fm Page 96 Thursday, March 1, 2007 2:15 PM 96 A Guide to MATLAB Object-Oriented Programming to read and write any field in the structure Mutation does not carry into the object, but once a client has a structure, the object is usually forgotten Unfortunately, there is no way to prevent a client from using builtin For this very reason, clients should be told about builtin and strongly cautioned against its use There is no conceivable reason for a client to circumvent the behavior of any type-specific member function by using a call to builtin This decision belongs to a class developer and not a client Class developers can and often use builtin to coerce MATLAB into doing work for them; however, if class developers are doing their job properly, it is extremely rare for a client to have the same need This is particularly true with struct 7.2 CODE DEVELOPMENT The first time we noticed a need for a function like struct was during the implementation of display We didn’t yet have such a function, so we resorted to building the structure in line The code used in display built a structure for a scalar object, and it will serve as a decent starting point for the tailored, nonscalar version of struct All we have to is adapt and generalize The important lines of code from display are repeated below public_struct.Size = this.mSize; public_struct.ColorRgb = subsref(this, substruct('.', 'ColorRgb')); This code has three problems: the use of public names in-line conversions from private variables to public only works on scalar objects The first problem is easily solved by calling our newly tailored version of fieldnames We never need to hard-code the public names because we can easily get them in the form of a cellstr The second problem is solved by realizing that subsref already includes the necessary conversions In fact, lines 2–3 above already use subsref Code in the generalized version of display must always use subsref to obtain public member values Using both fieldnames and subsref allows for a non-class-specific implementation The third problem isn’t hard to solve, but it does require a for loop The initial implementation is shown in Code Listing 41 Code Listing 41, Initial Implementation for struct.m function public_struct = struct(this) names = fieldnames(this); % tailored version returns public names values = cell(length(names), length(this(:))); % preallocate for k = 1:length(names) [values{k, :}] = subsref(this(:), substruct('.', names {k})); end public_struct = reshape(cell2struct(values, names, 1), size(this)); C911X_C007.fm Page 97 Thursday, March 1, 2007 2:15 PM struct.m 97 As the solution to problem 1, line calls fieldnames to get a cellstr of public member variable names Now that we have the names, we need values Line preallocates an empty cell array where the values will be stored The size of the cell array is length(names) × length(this) or, equivalently, the number of public variables × the number of objects in the array Line loops over the names, and line assigns public values We avoid a double loop because the whole object array is passed into subsref and subsref returns length(this) answers The magic of list expansion allows the assignment of multiple cell array elements Finally, line uses cell2struct to generate the structure as a row vector, and reshape converts the row into the same shape as this The function cell2struct is very powerful but somewhat obscure The structure values and names are passed into cell2struct as cell arrays The third argument tells cell2struct how to assign values in the values cell array to fieldnames in the names cell array In the case of line 7, a breaks up values into columns Each value in the column is associated index for index with a name in names After cell2struct, the resulting structure array will be × size(values,2) 7.3 THE TEST DRIVE The test drive for struct is easy because there aren’t many options The results are shown in Code Listing 42 Line builds an object, and lines 4–5 set some values Line returns the public structure Because the returned value is a structure, we can use the full_display utility function if we want more detail Lines 10–12 show the details, and the values match those assigned in lines 4–5 Line 13 uses a horzcat operator to create an object array Line 14 obtains the structure array, and lines 19–23 display the details Again, the detailed values match the values expected Code Listing 42, Chapter Test Drive Command Listing for struct.m 10 11 12 13 14 15 16 17 18 19 20 21 22 23 >> cd /oop_guide/chapter_7 >> clear classes; clc >> shape = cShape; >> shape.Size = 2; >> shape.ColorRgb = [1;1;1]; >> struct(shape) ans = Size: [2x1 double] ColorHsv: [3x1 double] >> full_display(ans) ans.Size = [2 2]'; ans.ColorRgb = [1 1]'; >> shape = [cShape shape]; >> struct(shape) ans = 1x2 struct array with fields: Size ColorRgb >> full_display(ans) ans(1, 1).Size = [1 1]'; ans(1, 1).ColorRgb = [0 1]'; ans(1, 2).Size = [2 2]'; ans(1, 2).ColorRgb = [1 1]'; C911X_C007.fm Page 98 Thursday, March 1, 2007 2:15 PM 98 A Guide to MATLAB Object-Oriented Programming 7.4 SUMMARY This function, while simple, is important because it closes a huge hole in the object’s encapsulation Now clients are presented with a uniform public front because display, fieldnames, and struct all advertise the same variables The tailored version of struct takes advantage of code modularity relying on fieldnames and subsref to return public information Notice that no class-dependent data are contained inside the implementation of struct The tailored version also supports modularity by allowing other functions to obtain the public structure without having to resort to in-line code Member functions can now take advantage of this support, and eventually we will modify some of the code in display to use both struct and fieldnames 7.5 INDEPENDENT INVESTIGATIONS Try to overload builtin and see what happens Modify display.m to take advantage of struct Modify developer_view (a subfunction inside display.m) to take advantage of fieldnames C911X_C008.fm Page 99 Thursday, March 1, 2007 2:24 PM get.m, set.m One of the exercises back in Chapter asked you to examine the possible benefits of developing one get and one set instead of a get and set pair for every public variable That was before the implementations of subsref and subsasgn Since subsref and subsasgn provide such an elegant, natural interface, perhaps there is no longer a need for get or set There are still benefits, but it seems the most compelling reasons were stolen away by subsref and subsasgn In this chapter, we will examine some of the benefits and define implementations for get and set that add quite a lot of flexibility The functions get and set complete the membership roles for the group of eight 8.1 ARGUMENTS FOR THE MEMBER FUNCTIONS GET AND SET A general get and set pair is still useful to both developers and clients A get and set pair helps simplify syntax and increases code modularity In special circumstances, get and set can be used to “conceal” object data So-called concealed data are variables that shouldn’t be part of the typical interface but still might be needed from time to time A get and set pair can provide abbreviated information about the class in the same way that get(0) and set(0) provide information about the command environment Finally, defining a get and set pair allows tab completion to work with objects Without a get and set pair, tab completion displays a list of private variables By closing another gap in MATLAB’s default encapsulation, the deal for developing get.m and set.m is sealed 8.1.1 FOR DEVELOPERS Switch statements inside subsref and subsasgn convert between private data and the public interface Often, the conversion code is simple and can be included directly in each case In these cases, private-public conversion can only be accomplished using subsref or subsasgn For clients, operator-syntax conversion automatically formats the arguments From inside the class, subsref or subsasgn syntax is cumbersome Using substruct to pack the index helps, but dot-reference access to public variables should be easier For example, the current implementation of display uses the command [values{k, :}] = subsref(this(:), substruct(‘.’, names{k})); Using get makes the command easier to read In that case, the command uses the modified syntax [values{k, :}] = get(this(:), names{k}); While this change might seem insignificant, it has a big impact on maintainability because the get syntax is easier to read at a glance Instead of “inventing” new function names like get and set, we could have tailored getfield and setfield There are several reasons why get and set are better First, in version 7.0, getfield and setfield are deprecated functions, i.e., they may not exist in future versions We certainly don’t want to develop new classes based on obsolete functions Second, the argument syntax for getfield and setfield is too complicated By using get and set, we don’t need to support a complicated predefined syntax Third, if we don’t overload getfield and setfield, MATLAB automatically converts them into subsref and subsasgn calls Finally, we 99 C911X_C008.fm Page 100 Thursday, March 1, 2007 2:24 PM 100 A Guide to MATLAB Object-Oriented Programming are not really inventing the names get and set These functions are already used to manipulate the command environment and for graphics handles Indeed, the environment and graphics handles look a lot like objects Even more important, tab completion uses get and set to obtain the completion list Clients primarily use access-operator syntax This opens the possibility of concealing special functionality inside get or set For example, even when shape.mDisplayFunc = ‘developer_view’; throws a “field not found” error, mutation can be accomplished by calling set directly The equivalent direct-call syntax looks like the following: shape = set(shape, ‘mDisplayFunc’, ‘developer_view’); To make this happen, both subsasgn and set must be properly implemented This kind of concealed functionality might be used to support development, test, or quality assurance Developers, testers, and inspectors usually demand more access to internal states compared to normal clients It is also an easy way to include developer-level capability without advertising it as public Concealed functionality still has public visibility because there are no formal checks that can be used to limit access to these so-called special-access variables This makes it difficult to decide when to promote the visibility of a private variable to concealed Consider mDisplayFunc as an example How we decide whether to keep mDisplayFunc private or promote its visibility to concealed or even public? If we leave it as private, developers must modify the constructor or add a member function to assign a value If we promote it to public visibility, then we need to document its behavior along with that of all the other public variables An interface description that includes many obscure or special-use functions can make a simple class appear overwhelming True public visibility also requires more diligence by developers to trap error conditions and protect class integrity Concealed visibility is a gray area There is more latitude in the documentation as well as with safety The answer usually comes down to purpose and complexity In general, it is unwise to add too much concealed functionality You want clients to respect the boundaries imposed by the interface, and adding a lot of concealed functionality promotes bad habits 8.1.2 FOR CLIENTS We generally discourage clients from using get and set in their source code; however, during development, get and set can provide a quick summary of the public variables Using get and set with graphic handles provides a good example The command window is another example Open MATLAB and enter the commands get(0) and set(0) in the command window For reference, the first few lines of each command are shown in Code Listing 43 With get(0), you get a display that includes all the “get-able” variables along with their current values The output is very similar to a structure display With set(0), you get a display that includes all the “setable” variables along with a list of possible assignment values Many times this is the only reminder you need The displays from graphics handles are similar Adding this capability to every class makes the use of objects more agreeable With the added benefits, clients might actually prefer objects to structures The outputs in Code Listing 43 are also interesting for another reason The list of “get-able” variables is different from the list of “set-able” variables Just like the public variables in our objects, certain variables are read-write while others are read-only Now that we are comfortable with encapsulation, we recognize this as the rule rather than an exception Both the command window settings and graphics handles seem much more like objects than like structures C911X_C008.fm Page 101 Thursday, March 1, 2007 2:24 PM get.m, set.m 101 Code Listing 43, Output Example for Built-In get and set 10 11 12 13 14 15 16 17 >> get(0) CallbackObject = [] CommandWindowSize = [134 26] CurrentFigure = [] Diary = off DiaryFile = diary Echo = off FixedWidthFontName = Courier FormatSpacing = loose >> set(0) CurrentFigure Diary: [ on | off ] DiaryFile Echo: [ on | off ] FixedWidthFontName FormatSpacing: [ loose | compact ] 8.1.3 TAB COMPLETION A very convenient command-line option is “tab completion.” With tab completion, you type the first few characters of a command or variable name and hit the Tab key At that point, MATLAB will either fill in the rest of the command or display a list of items that begin with the characters typed This helps speed development and reduces the burden of remembering complete command or variable names Tab completion calls on get and set to populate the name list If we don’t implement get and set, the name list isn’t empty Instead, it contains the names of the class’ private variables An empty list would be better because the list of private names represents another breach of encapsulation In this case, the list of private names is also worthless If we accept a name from the list, we will be presented with an error message telling us that it is illegal to access an object’s private variables There is really no choice: we must tailor get and set for every class 8.2 CODE DEVELOPMENT Inside get and set, a switch statement will be used to steer the execution into the correct public case In fact, the switch statements needed by get and set already exist inside the dot-reference sections of subsref and subsasgn, respectively The function calls are a little different, but if we grab the dot-reference switch code and wrap it in a new interface the implementation is quick and easy During the implementation for get and set, you will notice a lot of code duplication between get and subsref and between set and subsasgn In fact, the dot-reference switches can be replaced by calls to get or set In this chapter, the focus centers on the implementations of get and set In the next chapter, we will clean up code in several group-of-eight functions by replacing in-line code with calls to fieldnames, struct, get, and set C911X_C008.fm Page 102 Thursday, March 1, 2007 2:24 PM 102 A Guide to MATLAB Object-Oriented Programming 8.2.1 IMPLEMENTING GET AND SET The implementations for get and set need to three things: access and mutate public variables, access and mutate concealed variables, and display summary information To access and mutate public variables, we will copy the switch cases from subsref and subsasgn into get and set To implement concealed variables, get and set need code to allow them to figure out from where they were called The easiest way to figure this out is to examine the format of the input arguments The input arguments also steer the execution to display summary information Too few input arguments will trigger get and set to display a summary Because the arguments are used to steer the execution, we need to examine them more closely The function definitions listing all arguments are given by the following: function varargout = get(this, index) function varargout = set(this, index, varargin) The functions are member functions, and consequently the object occupies the first argument position In addition, in both functions the index variable occupies the second position The format of index will be used to grant or deny access to the concealed variables When index is a simple string, get and set will allow access to concealed variables In this case, switch statements can use the value without modification because it already names the desired variable When index is not a string, get and set will deny access to concealed variables In this case, get and set assume a substruct format for index The element at index (1) will specify dot-reference so that substruct, index (1).type will be equal to ‘.’ and index (1).subs is the string value used for the switch At first, allowing two formats for index might seem odd, but it turns out to be very convenient A typical call to get might look something like the following: shape_size = get(shape, ‘Size’); Here, passing the public name as the index simplifies the syntax The simple arguments also match the typical syntax for getfield We don’t specify a dot-reference operator because get is specifically tailored to return public variables The dot-reference operator is inherent in its operation On the other hand, when a public variable is accessed using operator syntax, for example, shape_size = shape.Size; MATLAB automatically packages the indices into a substruct The substruct index is passed into subsref or subsasgn, and the dot-referenced public variable name is contained in index(1).subs Under these conditions, subsref and get should behave the same way The same is true for subsasgn and set Because they share the same behavior, it is smart to let them share the code that implements the behavior One way to this is to allow get and set to perform the actual dot-reference indexing and let subsref call get and subsasgn call set We can even use the substruct index passed into subsref or subsasgn as a cue to disallow access to concealed variables In this chapter, we won’t make changes to subsref or subsasgn, but we will implement get and set so that the changes are easier to make when we get to §10.1.1.3 and §10.1.1.4 The number of input arguments is used to select between access/mutate or summary display Calling get or set with only one argument, for example, get(shape) % shape is an object of type cShape set(cShape) % constructor creates a temporary object C911X_C008.fm Page 103 Thursday, March 1, 2007 2:24 PM get.m, set.m 103 results in a summary display of all “get-able” or “set-able” public variables Calling set with two arguments, for example, set(cShape, ‘Size’) results in a summary display of the indexed variable only When this is a scalar object, get returns one value and set assigns one value When this is nonscalar, get returns a cell array composed of one value from each object in the object array In addition, when this is nonscalar, set potentially needs more than one assignment value In the calling syntax, the values appear as a comma-separated list MATLAB packages the commaseparated arguments into individual cells of varargin Execution based on both the number and type of the input arguments leads to an implementation with several logical paths Supporting public and concealed variables adds a few more The implementations will be easier to follow if we first construct a high-level block diagram We are now in a position to draw a high-level block diagram for these functions The block diagrams are shown in Figure 8.1 and Figure 8.2 The logical flow is similar for both because in many ways they both the same sort of things They have to check the number of input arguments, search the public names, determine whether concealed access is allowed, throw an error for unknown names, and convert between public and private data The diagram for set is a little more complicated because of its support for both full and subset summary displays Similarities allow the implementations to share the same general structure The initial implementations of get and set are shown in Code Listing 44 and Code Listing 45 get no no no Allow Concealed Access? no Variable Name is a public variable? nargin == ? yes yes yes Display summary get info Variable Name is a concealed variable? Error yes Get values from the object and put them in varargout return varargout FIGURE 8.1 get’s functional block diagram C911X_C008.fm Page 104 Thursday, March 1, 2007 2:24 PM 104 A Guide to MATLAB Object-Oriented Programming set no no no no Allow Concealed Access? no nargin == ? Variable Name is a public variable? nargin == ? yes yes yes yes Display subset summary set info Variable Name is a concealed variable? Display full summary set info yes Assign input values into the object Error return this FIGURE 8.2 set’s functional block diagram 8.2.2 INITIAL GET.M The implementation in Code Listing 44 follows the block diagram in Figure 8.1, and much of the code should look at least vaguely familiar The public variable cases in lines 23–41 came directly from the implementation of subsref in Chapter Code Listing 44, Initial Implementation for get.m 10 11 12 13 14 15 function varargout = get(this, index) % one argument, display info and return if nargin == if nargout == disp(struct(this(1))); else varargout = cell(1,max([1, nargout])); varargout{1} = struct(this(1)); end return; end % if index is a string, we will allow special access called_by_name = ischar(index); C911X_C008.fm Page 105 Thursday, March 1, 2007 2:24 PM get.m, set.m 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 105 % the set switch below needs a substruct if called_by_name index = substruct('.', index); end % public-member-variable section found = true; % otherwise-case will flip to false switch index(1).subs case 'Size' if isempty(this) varargout = {}; else varargout = {this.mSize}; end case 'ColorRgb' if isempty(this) varargout = {}; else rgb = hsv2rgb([this.mColorHsv]')'; varargout = mat2cell(rgb, 3, ones(1, size(rgb,2))); end otherwise found = false; % didn't find it in the public section end % concealed member variables, not strictly public if ~found && called_by_name found = true; switch index(1).subs case 'mDisplayFunc' if isempty(this) varargout = {}; else varargout = {this.mDisplayFunc}; end otherwise found = false; % didn't find it in the special section end end if ~found error(['??? Reference to non-existent field ' index(1).subs '.']); end if length(varargout) > & nargout C911X_C008.fm Page 108 Thursday, March 1, 2007 2:24 PM 108 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 A Guide to MATLAB Object-Oriented Programming this.mSize = subsasgn(this.mSize, index(2:end), varargin{:}); this.mScale = subsasgn(this.mScale, index(2:end), 1); else new_size = zeros(2, length(varargin)); for k = 1:size(new_size, 2) try new_size(:, k) = varargin{k}(:); catch error('Size must be a scalar or length == 2'); end end new_size = num2cell(new_size, 1); [this.mSize] = deal(new_size{:}); [this.mScale] = deal(ones(2,1)); end case 'ColorRgb' if length(index) > rgb = hsv2rgb(this.mColorHsv')'; rgb = subsasgn(rgb, index(2:end), varargin{:}); this.mColorHsv = rgb2hsv(rgb')'; else hsv = rgb2hsv([varargin{:}]')'; hsv = mat2cell(hsv, 3, ones(1, size(hsv,2))); [this.mColorHsv] = deal(hsv{:}); end otherwise found = false; end % concealed member variables, not strictly public if ~found && called_by_name found = true; switch index(1).subs case 'mDisplayFunc' if length(index) > this.mDisplayFunc = subsasgn(this.mDisplayFunc, index(2:end), varargin{:}); else [this.mDisplayFunc] = deal(varargin{:}); end otherwise found = false; % didn't find it in the special section end end C911X_C008.fm Page 109 Thursday, March 1, 2007 2:24 PM get.m, set.m 83 84 85 86 87 109 if ~found error(['??? Reference to non-existent field ' index(1).subs '.']); end varargout{1} = this; Lines 3–23 implement the first two true branches found in set’s block diagram and govern the behavior of the summary display Line uses the ‘-possible’ option added to the tailored version of fieldnames to obtain a cell array containing public names and their possible values The cell array format allows the struct command in line to create a structure with public names as fields and possible value strings as values When there is no requested output, lines 7–17 format and display summary information If only the object was passed, line displays the entire structure of public names and possible values If both object and index were passed, line 11 uses the index to create a temporary structure that contains only the indexed element Line 11 can assume that index is a string because subsasgn always passes at least three arguments Line 12 then displays the temporary structure If lines 11–12 cause an error, the warning on lines 14–15 is displayed The error might not actually be the result of a nonexistent field, but it is certainly the most likely error Tab completion will request an output, and lines 19–20 handle the request Line 19 allocates varargout with the correct number of elements, and line 20 assigns the structure of possible values into the first element With this structure, tab completion can populate the selection list If three or more arguments were passed, execution skips to line 25 Concealed access rights and index conversion commands are identical to the code in get Line 25 uses an ischar test to determine whether the index is a simple name string or something else The value called_by_name governs concealed variable mutation If index is a string, called_by_name is true and concealed mutation is permitted Lines 28–30 give index a uniform format by converting a string index into a substruct Again as in get, the remaining lines are organized into three functional blocks: public access (lines 33–64), concealed access (lines 67–81), and error processing (lines 83–85) The variable found is used to control entry into each of these blocks In the public variable block, line 22 sets found to true before attempting to match the indexed name with the public variable cases If one of the public variable cases matches the indexed name, the case assigns input values into the indexed variable of this and found remains true Otherwise, line 38 sets found to false The commands contained in each case were described line by line in Chapter Different from the Chapter description is how the input values are indexed In subsasgn, access-operator conversion reverses the order of the input values With set, there is no operator conversion and the input values are correctly ordered Line 67 guards the concealed variable block The guard allows entry only when the calling syntax supports concealed variables mutation and the indexed name has not yet been found The variable called_by_name is true if concealed mutation is permitted Once entered, the concealed variable block operates the same as the public variable block Of course, the cases contain concealed variable names rather than public variable names Line 68 sets found to true before attempting to match the indexed name with a case If one of the concealed variable cases matches the indexed name, the case assigns input values into the indexed variable of this and found remains true Otherwise, line 79 sets found to false Notice that on line 70, mDisplayFunc is a writeable concealed variable The only difference between this case and the case described in Chapter is the index order of the input values Line 83 guards the field not found error If the indexed field didn’t match an available case, found will be false and line 84 throws an error The syntax mimics the error message generated C911X_C008.fm Page 110 Thursday, March 1, 2007 2:24 PM 110 A Guide to MATLAB Object-Oriented Programming when a structure is dot-referenced with a name that does not match one of its elements If the indexed field matches a case, found will be true and this will contain mutated values Line 87 returns this as the first and only element of varargout even when nargout==0 8.3 THE TEST DRIVE In the test drive, we will test both the typical string-name syntax and the substruct syntax In the next chapter, the substruct syntax option will be used to support subsref and subsasgn, and we need to make sure get and set are ready We will use the values from the test drive in Chapter Instead of dot-reference operators, we will use calls to get and set We can also use mDisplayFunc to experiment with concealed variables Some commands and outputs for get and set are shown in Code Listing 46 and Code Listing 47 Code Listing 46, Chapter Test Drive Command Listing for set.m 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 >> >> >> >> >> >> >> >> >> >> >> cd 'C:/oop_guide/chapter_8' clear classes; fclose all; close all force; diary off; clc; shape(1) = cShape; shape(2) = shape(1); shape(2:3) = [shape(1) shape(2)]; shape(2) = set(shape(2), 'Size', [2;3]); shape(2) = set(shape(2), substruct('.', 'Size'), [2;3]); shape = set(shape, 'Size', [10;11], [20;21], [30;31]); shape(2) = set(shape(2), 'ColorRgb', [0 0]'); shape(3) = set(shape(3), 'ColorRgb', [0 0.5 0.5]'); set(shape) Size: {'double array (2x1)'} ColorRgb: {'double array (3x1)'} >> set(shape, 'Size') Size: {'double array (2x1)'} >> shape = set(shape, 'mDisplayFunc', 'developer_view'); >> shape(1) - Public Member Variables ans = Size: [2x1 double] ColorRgb: [3x1 double] Private Member Variables ans(1).mSize = [10 11]'; ans(1).mScale = [1 1]'; ans(1).mColorHsv = [0.66667 1]'; ans(1).mDisplayFunc = 'developer_view'; >> shape(1) = set(shape(1), substruct('.', 'mDisplayFunc'), []); ??? Error using ==> cShape.set ??? Reference to non-existent field mDisplayFunc C911X_C008.fm Page 111 Thursday, March 1, 2007 2:24 PM get.m, set.m 111 Line changes to this chapter’s directory, and line clears the workspace Lines 3–5 construct an object array Line sets shape(2)’s ‘Size’ public variable using name-string syntax, and line repeats the command using substruct syntax Lines 8–10 assign values we will check when we get to display public variables Line 11 demonstrates the one-input summary display Lines 12–13 display the public variable names along with the allowed value syntax Line 14 demonstrates the output of an indexed summary display The output on line 15 matches the first line of the one-input summary display Line 16 sets the concealed variable ‘mDisplayFunc’, and lines 17–26 demonstrate the resulting expanded output Notice that line 16 mutated all three objects in the array even though only one input value was provided For reference, line supplied three input values Line 27 attempts to set ‘mDisplayFunc’ using substruct syntax Lines 28–29 correctly complain that ‘mDisplayFunc’ is not a field This is correct because substruct syntax can’t be used to mutate concealed variables Code Listing 47, Chapter Test Drive Command Listing for get.m 10 11 12 13 14 15 16 17 >> get(shape, 'Size') ans = 10 20 30 11 21 31 >> get(shape(2), 'ColorRgb') ans = >> get(shape(3), 'ColorRgb') ans = 5.0000e-001 5.0000e-001 >> get(shape) Size: [2x1 double] ColorRgb: [3x1 double] Lines 1–4 confirm that set does not need to reverse the input values The values are correct, but the line outputs are concatenated because nargout is zero Lines 5–14 confirm that RGB values written into the object are the same values accessed Finally, lines 15–17 demonstrate the use of get’s summary display 8.4 SUMMARY In this chapter, we closed all the remaining holes in MATLAB’s default encapsulation Defining get and set enables effective tab completion, provides a handy summary of the public member variables, introduces concealed variable visibility, and gives class developers a friendly syntax for accessing public variables The implementations for get and set borrow heavily from Chapter 4, but the code is better organized The organization will immediately allow simplifications to subsref and subsasgn Later the organization will easily support inheritance The previous few chapters added many pieces to the implementation, but we have neglected to add those pieces to our puzzle With recent additions of fieldnames, struct, get, and set, every group-of-eight function has an initial implementation We can and we will improve C911X_C008.fm Page 112 Thursday, March 1, 2007 2:24 PM 112 A Guide to MATLAB Object-Oriented Programming MATLAB Function Search Rules builtin superiorto Member Variables Concealed inferiorto struct Member Functions Accessor Constructor Mutator Variables subsref subsasgn fieldnames struct get display set class call public Encapsulation Overloading private @ Directory FIGURE 8.3 All the pieces of the frame are in place them, but now that all have an implementation, the frame of the puzzle is complete A picture of our progress is shown in Figure 8.3 The rest of the development focuses on improving what we have already developed and on extending the scope of the framework 8.5 INDEPENDENT INVESTIGATIONS Give get the ability to accept a cellstr with multiple public member variable names How should return values be organized? Is it a lot easier to support scalar objects compared to general object arrays? Give set the ability to accept a cellstr with multiple public member variable names and a cell array of input values How does object array support complicate the code? C911X_C009.fm Page 113 Thursday, March 1, 2007 2:28 PM Simplify Using get, set, fieldnames, and struct Throughout this section, we have developed the implementations for a small but very important collection of member functions In their order of development, the functions belonging to this socalled group-of-eight are as follows: default constructor (e.g., cShape) subsref subsasgn display fieldnames struct get set For the current implementations, we considered the following two goals: Make the class interface mimic the built-in structure interface Coerce MATLAB to as much of the work as possible For the most part, the group of eight successfully reproduces a structure-like interface It takes all eight to produce a robust reproduction The reproduction is so good that in many cases, clients will not even be aware they are using objects The group of eight also takes maximum advantage of function-search rules to allow MATLAB to find and use built-in functions Learning how to use an obscure built-in function is always preferable to developing a new function Before we start using the group-of-eight functions, we need to add another constraint and revisit our earlier implementations This second pass will create a collection of bulletproof functions that can be used to create a safe alternative to structures The additional constraint is to • collect class-specific code into the smallest possible set of functions Certainly low-level functions like fieldnames, get, and set need to include class-specific code, but subsref, subsasgn, and display may not In their current states, implementations for subsref, subsasgn, and display contain class-specific code simply because they were developed first In this chapter, we revisit these functions and make them class independent By the end of this chapter, half the functions in the group of eight can be copied from class to class with no additional class-specific tailoring This situation represents reuse at its best The four functions are struct, subsref, subsasgn, and display We spent a lot of time and effort designing and developing the implementations, and it is comforting to realize that a lot of that work will never be repeated 113 ... full_display(ans) ans (1, 1) .Size = [1 1]''; ans (1, 1) .ColorRgb = [0 1] ''; ans (1, 2).Size = [2 2]''; ans (1, 2).ColorRgb = [1 1]''; C 911 X_C0 07. fm Page 98 Thursday, March 1, 20 07 2 :15 PM 98 A Guide to MATLAB. .. overload getfield and setfield, MATLAB automatically converts them into subsref and subsasgn calls Finally, we 99 C 911 X_C008.fm Page 10 0 Thursday, March 1, 20 07 2:24 PM 10 0 A Guide to MATLAB Object- Oriented. .. C 911 X_C008.fm Page 10 8 Thursday, March 1, 20 07 2:24 PM 10 8 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81

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

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan