CRC.Press A Guide to MATLAB Object Oriented Programming May.2007 Episode 2 Part 6 docx

20 230 0
CRC.Press A Guide to MATLAB Object Oriented Programming May.2007 Episode 2 Part 6 docx

Đ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

274 A Guide to MATLAB Object-Oriented Programming 18 >> star.Size = [2;3]; 19 >> disp(star.Size') 20 2 3 21 >> star 22 star = 23 Size: [2x1 double] 24 ColorRgb: [3x1 double] 25 Points: [2x6 double] 26 LineWeight: 'normal' 27 Title: 'A Star is born' 28 >> fieldnames(star) 29 ans = 30 'Size' 31 'ColorRgb' 32 'Points' 33 'LineWeight' 34 'Title' 35 >> fieldnames(star, '-full') 36 ans = 37 ans = 38 'Size % double array (2x1)' 39 'ColorRgb % double array (3x1)' 40 'Points % double array (2xN)' 41 'LineWeight % normal, bold' 42 'Title % string' 43 >> fieldnames(star, '-possible') 44 ans = 45 'Size' 46 {1x1 cell} 47 'ColorRgb' 48 {1x1 cell} 49 'Points' 50 {1x1 cell} 51 'LineWeight' 52 {1x1 cell} 53 'Title' 54 {1x1 cell} 55 >> struct(star) 56 Size: [2x1 double] 57 ColorRgb: [3x1 double] 58 Points: [2x6 double] 59 LineWeight: 'normal' 60 Title: 'A Star is born' 61 >> star = [cStar cStar; cStar cStar]; 62 >> size(star) 63 ans = 64 2 2 C911X_C018.fm Page 274 Friday, March 2, 2007 9:06 AM Class Wizard Versions of the Shape Hierarchy 275 Attending to the myriad details is something that a CASE tool can do very well. Even this is difficult unless there is a good organizational structure. The organizational structure advocated by the preceding chapters results in good class implementation, and Class Wizard is very helpful in maintaining that structure. This is particularly true when the class definition evolves. With Class Wizard, evolution is a simple matter of adding elements to the definition and rebuilding the files. Files managed by the tool are overwritten with the new definition, while handcrafted files are untouched. The best balance is always maintained between standard idioms and a developer’s creativity. 18.7 INDEPENDENT INVESTIGATIONS 1. Repeat the test-drive commands using cDiamond objects instead of cShape objects. 2. Modify the class interfaces to allow shapes to be rotated by an arbitrary angle. Use Class Wizard to generate the initial versions of helper functions and public member functions. 3. Add other line-style features to cLineStyle, and expose these features so that clients can use them with cStar and cDiamond objects (for example, dotted vs. solid lines). 4. Add a cCircle class to the hierarchy. Does cCircle inherit cShape or is there a better relationship? Should /@cCircle/draw use polar instead of plot? How would the use of polar change the organization? 65 >> [star.Size] 66 ans = 67 1 1 1 1 68 1 1 1 1 69 >> {star.Size} 70 ans = 71 [2x1 double] [2x1 double] [2x1 double] [2x1 double] 72 >> 73 >> disp(class(star)) 74 cStar 75 >> disp(isa(star, 'cShape')) 76 1 77 >> disp(isa(star, 'cDiamond')) 78 0 C911X_C018.fm Page 275 Friday, March 2, 2007 9:06 AM C911X_C018.fm Page 276 Friday, March 2, 2007 9:06 AM Part 3 Advanced Strategies In this section, we redeploy standard object-oriented techniques in a way that allows MATLAB to create a few special-purpose classes commonly found in other object-oriented languages. These include containers , singleton objects, functors , and iterators . These classes require strong encap- sulation and a flexible object-oriented language. The fact that these sophisticated classes can be created from elements that already exist pays tribute to the MATLAB design team. If these example classes make you wonder what else is possible, they have done their job. With a little imagination and creativity, anything is possible. Some of the topics in this section are controversial because they upset the status quo. Redefining member-function syntax, adding a pass-by-reference function model, and obtaining protected vis- ibility for variables and functions are probably the most disruptive topics. The discussions don’t try to judge whether you should adopt a particular technique, but instead try to demonstrate the flexibility inherent in MATLAB objects and expand the way you think about them. Some of the techniques are worthy of adoption, while others would benefit from more support from the language and the user community. Like many disruptive technologies, it is hard to know in advance what will be embraced. Unlike many languages, MATLAB’s evolution isn’t restricted by an ISO standard. If enough of us adopt a few of these techniques, market forces will ultimately prevail. C911X_S003.fm Page 277 Friday, March 2, 2007 9:09 AM C911X_S003.fm Page 278 Friday, March 2, 2007 9:09 AM 279 19 Composition and a Simple Container Class As a further demonstration of composition, we make an initial foray into designing and imple- menting a general container class. A general container is different from an array because it can hold different types. A general container is different from a cell array because all objects must descend from the same parent. For example, a general cShape container can hold both cStar and cDiamond objects because they both use cShape as a parent. A container is also different from a cell array because a container has a structure-like interface. The interface makes a container behave a lot like an object array. Rather than looping over each element in the container, clients can use vector syntax. Often the loop still exists; however, it is now hidden behind the container’s interface. Developing a set of standard containers compatible with the general computer-engineering literature* or with National Institute of Standards (NIST) definitions** would be an enormous undertaking. The goals for this chapter’s container are much less ambitious. The primary goal is to demonstrate one potential use of composition. A secondary goal is to produce a container that might be useful as is, or at least produce a container that can be easily improved. The container developed for this chapter isn’t perfect, but with what you already know, you can fix all of its deficiencies. 19.1 BUILDING CONTAINERS To implement a container, several details are important. First, we need to specify the object type held by the container. Any object that passes an isa test for the specified type will be allowed in. Thus, objects of the specified type and objects using the specified type as a parent are okay to add to the container. For the example, we will specify cShape as the object type. That will allow the container to hold cShape , cStar , and cDiamond objects. If we want to create new shape classes, the container will hold them too. Of course, these new classes must have cShape somewhere in their hierarchy so that isa(object, ‘cShape’) returns true . The next thing we need to decide is how the container implementation will store the objects. MATLAB will not let us use a built-in type, like cell , as a parent, so we must look for an alternative. There are two options but both represent compromises. The first and probably the most obvious approach stores objects in a private cell array. Cell array storage is probably the best approach because it aligns public and private indices. One potential problem with this approach is the mismatch among built-in functions like length and size and the number of objects held in the container. Of course, we will code around this problem by overloading length and size . We might also want to consider overloading reshape , ndims , numel , num2cell , and mat2cell , among others. The next potential problem with a private cell array is the index value end . Using end to add a new element to the container should work the same as adding an element to an array. For example, the command syntax might look like the following: * Cardelli, L., and Wegner, P. “On Understanding Types, Data Abstraction and Polymorphism,” ACM Computer Survey , 17, 4, December 1985, 471–522. ** http://www.nist.gov/dads/. C911X_C019.fm Page 279 Friday, March 2, 2007 9:42 AM 280 A Guide to MATLAB Object-Oriented Programming shape_array(end+1) = cStar; The built-in behavior of end returns the dimension of shape_array , not the dimension of the private cell array inside shape_array . Redefining size and length doesn’t help, but thanks to the foresight of the MATLAB developers, we can code around this problem too. In this situation, end acts like an operator. Like any operator, MATLAB converts end into a function call. This behavior allows us to overload the function end.m to return an appropriate value. An alternate container solution avoids length , size , reshape , and end issues by taking advantage of the way MATLAB implements structures. For example, the container class might include a private member variable named mObject . After several additions, class(this(1).mObject) might equal ‘cStar’ and class(this(2).mObject) might equal ‘cDiamond’ . MATLAB allows different object types stored in the mObject element to coexist. As long as we never try to concatenate mObject elements (i.e., [this.mObject] ), everything will work fine. With this solution, adding a new object simply increases the size of the private structure. The primary problem with this approach involves repeating the container’s private structure and the fact that arrays of structures are memory hogs. Using repmat can also produce inconsistent results. Regardless of the approach, we also need to consider concatenation with cat , horzcat , and vertcat . Achieving the best compatibility means supporting the concatenation of a container and an object and the concatenation of two or more containers. We usually don’t want to restrict the concatenation order, and that means the container must be superiorto the classes it holds. 19.2 CONTAINER IMPLEMENTATION For implementation purposes, this chapter uses the cell-array approach. With the cell-array approach, the container object itself is never empty even when the private cell array contains no objects. This eliminates the potential for empty-object memory errors that sometimes arise.* The cell-array approach requires a little more work up front, but the result seems to be more robust compared to the object-array approach. After the first container implementation, the added workload isn’t a problem because most of the tailored functions can be copied, as is, to other container implementations. The implementation example is organized into three sections. The first section focuses on our standard group-of-eight framework. The second section focuses on a set of tailored functions that overload the behavior of standard MATLAB built-in functions. The third section focuses on cShape -specific functions. The implementation of any container can be organized along these divisions. 19.2.1 T HE S TANDARD F RAMEWORK AND THE G ROUP OF E IGHT Even though a container class is quite different from the other class examples, we don’t have to code everything from scratch. Instead, use Class Wizard to generate the initial set of files and modify them to suit the needs of the container. The constructor, ctor_ini , ctor_1 , display , parent_list , and struct won’t need modifications. The remaining group-of-eight functions — fieldnames , get, set, subsref, and subsasgn — will need container-specific changes. The changes are modest and are relatively easy since the generated code serves as a guide. The data entered into Class Wizard are provided in Table 19.1 through Table 19.4. The list of function names in Table 19.3 provides a preview of the tailoring to come. Fields not listed in the tables should remain set to their default values. The complete Class Wizard mat file and the unmodified * Versions 7.1 and earlier are not stable when repmat is used to create an object array with a dimension size equal to zero. Returning a so-called empty object from a constructor is particularly bad. The fact that a default-constructed container should be empty makes the repeated-structure approach unreliable in these versions. C911X_C019.fm Page 280 Friday, March 2, 2007 9:42 AM Composition and a Simple Container Class 281 results are included in /chapter_0/as_generated cShapeArray. After entering the data, generate the class. The container itself contains no public member variables, and, as generated by Class Wizard, the public variable sections inside fieldnames, get, and set are empty. These sections will not remain empty. Instead, these functions will forward public variable requests to the secondary objects stored in the container. The Class Wizard cases inside subsref and subsasgn also need some changes. The initial code assumes the container itself is an array. In reality, the container class is always scalar. Changes to subsref and subsasgn use the private cell array to make the container look like an array. The dot-reference case is okay because changes to get and set determine dot-reference behavior. The array-reference case needs to access and mutate objects held in the container’s cell array. Only the highlights are included in the following sections. The fully modified files are included in /chapter_0/@cShapeArray. 19.2.1.1 Container Modifications to fieldnames Since the container itself has no public variables, fieldnames.m doesn’t initially contain a list of public names. This is correct because only the objects held by the container have public variables. The container needs to return a list of public names, but it doesn’t need an explicit list. Rather than coding an explicit name list inside the container’s version of fieldnames, we simply forward the fieldnames request and collect the result. There are two potential targets for the forward: the class type held in this.mType (see Table 19.2) and the objects held in this.mArray (see Table 19.2). Choosing the first returns the public members allocated to the parent. These names are guaranteed to exist for every object in the container. Choosing the latter also includes parent- class public names, but it might also include public names defined for the children. Choosing the latter also means that any particular object may or may not contain every public variable listed. This is not necessarily a problem, but it is something that must be considered when container functions are implemented. For cShape and its children, most of the public variables are defined by the parent. In this situation, using the container class type held in this.mType is a good choice. This choice also TABLE 19.1 cShapeArray Class Wizard Main Dialog Fields Field Value Class Name cShapeArray Superior To cShape, cStar, cDiamond, double TABLE 19.2 cShapeArray Private Variable Dialog Fields Private Variable Name Initial Value Comment mType ‘cShape’ Container can hold any object that passes isa(object, this.mType). mArray {} Cell array for the container. mFigHandle [] Figure handle where all contained shapes are drawn. C911X_C019.fm Page 281 Friday, March 2, 2007 9:42 AM 282 A Guide to MATLAB Object-Oriented Programming TABLE 19.3 cShapeArray Public Function Field Values Function Name Input Argument List Output Argument List Comment draw this, FigureHandle this Calls draw for every object in the container. If FigureHandle is not passed in, draw will manage the use or creation of a figure window. end this, k, n num Redefines built-in behavior. Returns an index value consistent with “end.” If n is not equal to length(size(this.mObject)), some reshaping is done to find the correct value. length this num Redefines built-in behavior. Returns the correct length based on the number of objects in the container. mat2cell this, varargin Redefines built-in behavior. Function is not supported; throws an error if called. mtimes lhs, rhs this Redefines built-in behavior for *. Allows multiplication between the container and arrays of doubles. times lhs, rhs this Redefines built-in behavior for *. Allows multiplication between the container and arrays of doubles. ndims this num Redefines built-in behavior. Returns the correct ndims value based on the shape of the container’s mObject cell array. C911X_C019.fm Page 282 Friday, March 2, 2007 9:42 AM Composition and a Simple Container Class 283 allows the container to return a list of names even when the container is empty. Add the following command to the end of the initial version of @cShapeArray/fieldnames.m. names = [names; fieldnames(feval(this.mType), varargin{:})]; In this command, feval(this.mType) creates a temporary object and varargin{:} expands input arguments. The complete list of names is created by concatenating the return value with any names that already exist. To improve run time, the result could be assigned to a persistent variable. Use the profiler to determine when a persistent is warranted. 19.2.1.2 Container Modifications to subsref For dot-reference operations, the container needs to forward the operation to the objects held in the container. The best location for the forward isn’t in subsref but rather in get. Locating the forward inside get means no changes to subsref’s dot-reference case. For array-reference operations, the input index value is used to return elements in the container’s cell array. In the normal situation, the built-in version of subsref and MATLAB’s assignment operator cooperate to return a subset array with the same type as this. The container’s array-reference code can’t rely on the same built-in behavior. Instead, the code first constructs an empty container and then assigns the indexed subset into the new container’s mArray variable. Modifications to subsref’s array-reference case are shown in Code Listing 109. Line 2 instantiates a new container object by calling the constructor. Class(this) returns the name of the constructor and feval executes it. No arguments are passed with the function call so the result is an empty container. Line 3 uses index(1) to get the correct subset out of TABLE 19.3 (CONTINUED) cShapeArray Public Function Field Values Function Name Input Argument List Output Argument List Comment num2cell this, varargin container_ cells Redefines built-in behavior. Use this function to access the container’s entire cell array. Function only supports one input argument. If you try to pass in a direction, the function will throw an error. reset this this Calls reset for every object in the container. size this, varargin varargout Redefines built-in behavior. Returns the correct size array based on the number of objects in the container. Reshape this, varargin this Redefines built-in behavior. Reshapes the object cell array. C911X_C019.fm Page 283 Friday, March 2, 2007 9:42 AM [...]... expand_input to form an equivalent cell array of objects for every input C911X_C019.fm Page 29 2 Friday, March 2, 20 07 9: 42 AM 29 2 A Guide to MATLAB Object- Oriented Programming Code Listing 114, Overloading cat.m to Support Container Operations 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 function this = cat(dir, varargin) this = feval(mfilename('class'));... C911X_C019.fm Page 29 0 Friday, March 2, 20 07 9: 42 AM 29 0 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 A Guide to MATLAB Object- Oriented Programming otherwise found = false; % look in each object for k = 1:numel(this.mArray) if length(varargin) == 1 set_val = varargin{1}; else set_val = varargin{k}; end try this.mArray{k} = set(this.mArray{k}, index, set_val); found = true; catch err = lasterror;... otherwise-case will flip to false switch index(1).subs otherwise found = false; % look in each object for k = 1:numel(this.mArray) try varargout{k} = get(this.mArray{k}, index, varargin{:}); C911X_C019.fm Page 28 8 Friday, March 2, 20 07 9: 42 AM 28 8 9 10 11 12 13 14 15 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 A Guide to MATLAB Object- Oriented Programming. ..C911X_C019.fm Page 28 4 Friday, March 2, 20 07 9: 42 AM 28 4 A Guide to MATLAB Object- Oriented Programming TABLE 19.4 cShapeArray Data Dictionary Field Values Variable Name Type Comment container_cell cell array of objects Cell array of objects held in the container FigureHandle figure handle Used to pass around a handlegraphics figure handle K integer > 0 Specifies which dimension to inspect lhs double, container... isa(varargin{1}, this.mType) % an object that can indeed be held by the container C911X_C019.fm Page 28 6 Friday, March 2, 20 07 9: 42 AM 28 6 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 A Guide to MATLAB Object- Oriented Programming % might have a length > 1 set_val = num2cell(varargin{1}); this.mArray = subsasgn(this.mArray, index, set_val); is_empty = cellfun('isempty', this.mArray);... container, line 15 returns the private cell array, in_val.mArray For a compatible object array, line 18 converts the array into a cell array of objects and returns the result Processing for a cell array is more complicated because each element in the cell array can be a container, an object array, or another cell array Lines 22 25 loop over the cells, making a recursive call to expand_input The expanded... is a convenient alternative to inserting objects element by element Three functions are used for concatenation: cat, horzcat, and vertcat Horzcat and vertcat are particularly important because they have corresponding operator syntax For example, [container, star] is converted into a call to horzcat and [container; star] is converted into a call to vertcat The cat function has no corresponding operator,... container object into varargout If there are more indexing levels, lines 8–9 calls subsref 19 .2. 1.3 Container Modifications to subsasgn Container additions to subsasgn follow a pattern similar to the additions in subsref Subsasgn’s dot-reference case is okay because container-related modifications to set forward the operation to container’s objects Commands in the array-reference case are modified to target... Page 29 1 Friday, March 2, 20 07 9: 42 AM Composition and a Simple Container Class 29 1 Fortunately, MATLAB s object- oriented features allow us to overload and tailor the behavior for built-in functions Here we look at end, length, ndims, reshape, and size 19 .2. 2.1 Container-Tailored end In §19.1, the following use of end was highlighted: shape_array(end+1) = cStar; The built-in behavior of end is not appropriate... every object throws an error, line 10 or 39 will never execute, all varargout cells will be empty, and found will be false If even one object returns a value, line 10 or 39 assign found a value of true and at least one varargout cell will contain an assigned value The way found and varargout are managed means that not all objects in the container need an identical set of public or concealed variables . Page 28 5 Friday, March 2, 20 07 9: 42 AM 28 6 A Guide to MATLAB Object- Oriented Programming Lines 2 9 are already okay. Lines 2 9 detect when the input variable this is empty and take appropriate action container. mFigHandle [] Figure handle where all contained shapes are drawn. C911X_C019.fm Page 28 1 Friday, March 2, 20 07 9: 42 AM 28 2 A Guide to MATLAB Object- Oriented Programming TABLE 19.3 cShapeArray. >> disp(isa(star, 'cDiamond')) 78 0 C911X_C018.fm Page 27 5 Friday, March 2, 20 07 9: 06 AM C911X_C018.fm Page 27 6 Friday, March 2, 20 07 9: 06 AM Part 3 Advanced Strategies In

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

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

Tài liệu liên quan