A Guide to MATLAB Object-Oriented Programming phần 4 potx

38 356 0
A Guide to MATLAB Object-Oriented Programming phần 4 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

Displaying an Object’s State 89 full_display format. (Hint: build a public structure and call full_display.) Soon we will make this a lot easier. 3. Try to redefine MATLAB’s builtin display function to use full_display instead. Make this work for built-in types as well as for user-defined types. FIGURE 5.1 Puzzle with display and function handles. @ Directory Member Variables Member Functions Encapsulation struct class call Constructor Mutator Accessor MATLAB Function Search Rules subsref subsasgn public private Overloading builtin superiorto inferiorto display C911X_C005.fm Page 89 Thursday, March 1, 2007 2:06 PM C911X_C005.fm Page 90 Thursday, March 1, 2007 2:06 PM 91 6 fieldnames.m With the basic implementation behind us, we need to step up to the next level. We want to improve the implementations by making our classes more capable. With subsref and subsasgn , we set up public as a new category of member variables. In the tailored display function, we struggled to generate the structure-like output because a separate list of public variables is not available. In this chapter, we tailor fieldnames as a way to provide that list. The fieldnames function also plugs a leak in encapsulation. The built-in version of fieldnames returns a list of private names, a behavior we cannot tolerate. Tailoring fieldnames also improves the modularity in the group-of-eight implementation. For example, in display we were forced to add public names to the implementation. Other functions in the group of eight also need access to the names. By including a member function that returns the public list, we can reduce the number of places where public names are repeated. Based on its role with structures, a tailored version of fieldnames is the logical place for the list to exist. 6.1 FIELDNAMES While we could easily write a specific get function for this task (e.g., getPublicNames ), MATLAB already defines a suitable function. For structures, the built-in version of fieldnames will return a cellstr filled with element names. The built-in version will also operate on objects. If you examine help fieldnames , you will notice that built-in version claims to return a list of an object’s “public data fields.” Unfortunately, help’s use of “public” is confusing. First, we are well aware that every field in the object’s structure is private. We also know that our definition of public member variable comes about through the implementation of subsref and subsasgn . How is it possible for the built-in version of fieldnames to discover the names of the public variables? It isn’t. There must be a mismatch between help’s idea of public and ours. We can test the built-in version. What we find is that the built-in version actually returns the field names of the object’s underlying structure, that is, the names of the private member variables. This is not good. If we don’t correct this situation, we have another potential window into the private structure. We have already discussed why revealing the private part of an object is a bad idea, and the same arguments apply to fieldnames . This is simply another function that seems to be at odds with encapsulation goals. Of course, by now the solution path is clear. If we don’t like what we get from the built-in version, we simply supply a tailored version that suits our purposes. In this case, we will tailor fieldnames so that it properly returns a list of public member variables. This will allow clients to interface with objects using getfield , setfield , or dynamic fieldname syntax. 6.2 CODE DEVELOPMENT The built-in version of fieldnames accepts a structure as the input and returns a cellstr populated with the element names. The tailored version should work the same way for an object. Also, when used with objects, there is a more obscure syntax. A second string input with the value ‘-full’ can be passed into fieldnames . The ‘-full’ option tells fieldnames to add information about each field’s type, attributes, and inheritance. This option appears to be an extension for Java. For native MATLAB objects, type in particular does not make a lot of sense. C911X_C006.fm Page 91 Thursday, March 1, 2007 2:09 PM 92 A Guide to MATLAB Object-Oriented Programming The implementation will include code to process the ‘-full’ option, but its purpose and output format are not well specified with respect to native MATLAB objects. In the same way ‘-full’ appears to be a Java-related option, we will add an option related to the group-of-eight interface. Recall the discussion of the commands get(0) and set(0) . If possible, we should give objects a similar interface, that is, an interface where commands like get(cShape) and set(cShape) will return a brief summary of the public variables. Java objects have this ability, and it is very convenient. Most of the information displayed by these commands is information related to the public variable names, and not all of it the current value. This makes fieldnames a very logical place to store the additional data. The ‘-full’ option does not include everything we need. We need to invent a new string value that will be used primarily from inside other group-of-eight member functions. In the case of set(cShape) , the output needs to include a list of the allowed values for each element. The list describes the possible element values, and following from this, the new string value will be ‘-possible’ . When ‘-possible’ is the second argument to fieldnames , a special output format will be produced. The output will be a single cell array where odd-numbered elements contain the public member variable names and even-numbered elements contain a cell array filled with the allowed values for the preceding odd index name. If the set of allowed values is indeterminate, the cell array will be empty. The tailored version of fieldnames is shown in Code Listing 39. Like the other examples, this version is tailored for cShape . Other classes would follow the syntax in this example but encode different names, types, and allowable values. In the one-argument case, line 4 returns a cellstr with a list of public variable names. The names are hard-coded into the function. These names need to match the public cases in subsref or problems might arise later. Class developers are responsible for keeping the files synchronized. The switch on line 6 is evaluated when more than one argument is passed. Lines 8–9 assemble the cellstr return when the caller requests the ‘-full’ option. Lines 11–12 assemble the return when the caller requests ‘-possible’ . This is our option, so we are free to define any Code Listing 39, Initial Design for fieldnames.m 1 function names = fieldnames(this, varargin) 2 % returns the list of public member variable names 3 if nargin == 1 4 names = {'Size' 'ColorRgb'}'; % note: return as a column 5 else 6 switch varargin{1} 7 case '-full' 8 names = {'Size % double array' 9 'ColorRgb % double array'}'; 10 case '-possible' 11 names = {'Size' {{'double array (2x1)'}} 12 'ColorRgb' {{'double array (3x1)'}}}'; 13 otherwise 14 error('Unsupported call to fieldnames'); 15 end 16 end C911X_C006.fm Page 92 Thursday, March 1, 2007 2:09 PM fieldnames.m 93 syntax. The syntax in lines 11–12 allows each private variable to specify an allowed-value cellstr in addition to the name. This syntax makes it easier to separate and display the list of possible values. 6.3 THE TEST DRIVE The test drive for fieldnames is easy because there are only three possible options. The results are shown in Code Listing 40. Line 3 builds an object and line 4 gets the public name list by calling fieldnames with only one argument. By leaving off the semicolon, the display shows that the list is consistent with the public interface. Line 8 invokes the ‘-full’ option and the returned list includes names and some type information. Line 12 invokes the ‘-possible’ option. The return value for this option has a format that lends itself to direct conversion into a structure. Line 13 demonstrates the conversion and displays the structure result. 6.4 SUMMARY The fieldnames function, while simple, is important because it prevents the built-in version of fieldnames from advertising private areas of our objects. The function also supports code modularity by consolidating the names of the public member variables in one location. In Chapter 5, prior to the existence of fieldnames , the list of public names was twice hard-coded inside display.m . Now that fieldnames exists, display code can be refactored to eliminate the hard-coded list. The refactored version of display is presented in §9.3. The tailored version of fieldnames also supports a new option that will be used to display a convenient public member summary. As we continue to develop the group of eight, the importance of fieldnames will become more and more evident. Code Listing 40, Chapter 6 Test Drive Command Listing for fieldnames.m 1 >> cd /oop_guide/chapter_6 2 >> clear classes; clc 3 >> shape = cShape; 4 >> fieldnames(shape) 5 ans = 6 'Size' 7 'ColorRgb' 8 >> fieldnames(shape, '-full') 9 ans = 10 'Size % double array' 11 'ColorRgb % double array' 12 >> possible = fieldnames(shape, '-possible'); 13 >> struct(possible{:}) 14 ans = 15 Size: {'double array (2x1)'} 16 ColorRgb: {'double array (3x1)'} C911X_C006.fm Page 93 Thursday, March 1, 2007 2:09 PM 94 A Guide to MATLAB Object-Oriented Programming 6.5 INDEPENDENT INVESTIGATIONS 1. In the ‘-full’ case, use class to inspect and assign the field’s type. What are you going to do for object arrays? 2. Modify display.m to take advantage of fieldnames. C911X_C006.fm Page 94 Thursday, March 1, 2007 2:09 PM 95 7 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 C911X_C007.fm Page 95 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 do 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 do is adapt and generalize. The important lines of code from display are repeated below. This code has three problems: 1. the use of public names 2. in-line conversions from private variables to public 3. 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 conver- sions. 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. 1 public_struct.Size = this.mSize; 2 public_struct.ColorRgb = 3 subsref(this, substruct('.', 'ColorRgb')); Code Listing 41, Initial Implementation for struct.m 1 function public_struct = struct(this) 2 names = fieldnames(this); % tailored version returns public names 3 values = cell(length(names), length(this(:))); % preallocate 4 for k = 1:length(names) 5 [values{k, :}] = subsref(this(:), substruct('.', names {k})); 6 end 7 public_struct = reshape(cell2struct(values, names, 1), size(this)); C911X_C007.fm Page 96 Thursday, March 1, 2007 2:15 PM struct.m 97 As the solution to problem 1, line 3 calls fieldnames to get a cellstr of public member variable names. Now that we have the names, we need values. Line 3 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 4 loops over the names, and line 5 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 7 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 1 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 1 × 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 3 builds an object, and lines 4–5 set some values. Line 6 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 7 Test Drive Command Listing for struct.m 1 >> cd /oop_guide/chapter_7 2 >> clear classes; clc 3 >> shape = cShape; 4 >> shape.Size = 2; 5 >> shape.ColorRgb = [1;1;1]; 6 >> struct(shape) 7 ans = 8 Size: [2x1 double] 9 ColorHsv: [3x1 double] 10 >> full_display(ans) 11 ans.Size = [2 2]'; 12 ans.ColorRgb = [1 1 1]'; 13 >> shape = [cShape shape]; 14 >> struct(shape) 15 ans = 16 1x2 struct array with fields: 17 Size 18 ColorRgb 19 >> full_display(ans) 20 ans(1, 1).Size = [1 1]'; 21 ans(1, 1).ColorRgb = [0 0 1]'; 22 ans(1, 2).Size = [2 2]'; 23 ans(1, 2).ColorRgb = [1 1 1]'; C911X_C007.fm Page 97 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 1. Try to overload builtin and see what happens. 2. Modify display.m to take advantage of struct. 3. Modify developer_view (a subfunction inside display.m) to take advantage of fieldnames. C911X_C007.fm Page 98 Thursday, March 1, 2007 2:15 PM [...]... 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 A Guide to MATLAB Object-Oriented Programming eval(['display(' display_name ');']); else % array case % use eval to assign this into display_name variable eval([display_name ' = this;']); % use eval to call builtin display for size info eval(['builtin(''display'', ' display_name ');']); % still need to display variable names... 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. .. 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... Thursday, March 1, 2007 2: 24 PM 1 04 A Guide to MATLAB Object-Oriented Programming set no no no no Allow Concealed Access? no nargin == 2 ? Variable Name is a public variable? nargin == 1 ? 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... 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,... implementations for get and set need to do 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... array is greater than 1, all objects in the array should be drawn in the same figure Each element in the object array can stand on its own because each saves a copy of the figure handle When array elements are pulled out of an array or when arrays are concatenated, mismatches in the handle values can occur If a mismatch is detected during a draw, the object should close all mismatched figures and open a. .. 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. .. cases matches the indexed name, the case assigns public values into varargout and found remains true Otherwise, line 38 sets found to false The commands contained in each case were described line by line in Chapter 4 Line 42 guards the concealed variable block The guard allows entry only when the calling syntax allows access to concealed variables and the value has not yet been found The variable called_by_name... called_by_name is true if concealed access 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 43 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 concealed values . syntax, the values appear as a comma-separated list. MATLAB packages the comma- separated arguments into individual cells of varargin. Execution based on both the number and type of the input arguments. varargout Variable Name is a concealed variable? C911X_C008.fm Page 103 Thursday, March 1, 2007 2: 24 PM 1 04 A Guide to MATLAB Object-Oriented Programming 8.2.2 INITIAL GET.M The implementation. 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.

Ngày đăng: 09/08/2014, 12:22

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

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

Tài liệu liên quan