|
From: andreagiorgetta on 26 Aug 2007 10:11 Hi to all, I'm new to object design and I am designing an image organizer application (similar to Picasa). For image handling operation I have a class that interacts with the image processing component, and a Facade for that class. I also have a class that deals with GUI operations (for example, when you select a certain option, some data must be gotten from database and the screen must be updated to showit... GUI class would be doing that screen update operation). As a part of the GUI, I need to design an image composed of other images, and that involves to sequentially call methods implemented by the image processing class. My question is: Which would be the class which should implement a method (for example, getComposedImage) that do those sequential calls to the image class? Thanks in advance! Andrea Giorgetta PD: Sorry about my English, I am from Argentina, so it's not my primary language.
From: H. S. Lahman on 26 Aug 2007 13:14 Responding to Andreagiorgetta... > Hi to all, I'm new to object design and I am designing an image > organizer application (similar to Picasa). For image handling > operation I have a class that interacts with the image processing > component, and a Facade for that class. I also have a class that deals > with GUI operations (for example, when you select a certain option, > some data must be gotten from database and the screen must be updated > to showit... GUI class would be doing that screen update operation). > As a part of the GUI, I need to design an image composed of other > images, and that involves to sequentially call methods implemented by > the image processing class. My question is: Which would be the class > which should implement a method (for example, getComposedImage) that > do those sequential calls to the image class? I don't know anything about Picasa, but I will take your first sentence literally that the primary goal of the application is to organize images (e.g., composing complex images from simpler images). If so, then I would argue that is a quite different subject matter from rendering images in a GUI. Your second sentence implies that you have a separate component for the image processing (which I assume to mean rendering in the display). So far, so good. However, where I start to lose track is the class that interacts with the image processor and has a Facade. I can see having a Facade to hide the image processing; the Facade pattern is a de facto standard for implementing subsystem interfaces. What I don't understand is why the class interacting with the image processor needs a Facade. [Actually I do; in the Bridge Model subsystems have outgoing interfaces as well as inpcoming interfaces, but I suspect that is not what you meant.] Also, I am a bit concerned with a single GUI class. If you are going to be going exotic things like composing images in the application, I would expect the GUI rendering to be fairly complex, even surrounding a graphics pane where an image might be rendered. If so, I would expect that to be encapsulated in a subsystem with several classes that abstract the GUI paradigm (e.g., classes like Window, Menu, and Control). So what does that leave for the "main" application? I would expect that to be the mechanics of image storage and access at the file level, some abstract notion of combining images, and some supporting infrastructure to keep track of things so one knows was to render. They key is that the notion of composition would be at a higher level of abstraction than rendering of images. For example, if one wants a Pristine Landscape image, one needs Tree, Meadow, and Grazing Cow images to cobble together. IOW, one wants to think about What one cobbles together rather than How one cobbles it together. The most common way to deal with composing things like images in an OO context is to use relationships to capture the composition rules, such as: 1 R1 contains * [PristineLandscape] ------------------------ [Forest] | 1 | 1 | | | R2 | R3 | | | contains | contains | * 1 borders on * | * [Meadow] -------------------------------- [Tree] | 1 | graze on | | R4 | | * [Cow] One then depends upon instantiating the relationships to ensure proper participation in collaborations. For example, not all of the Trees in a Forest may border on a Meadow. One instantiates the objects and relationships based upon what the user selects in the GUI for composition elements. Once one has captured the organization of the composition in relationships one can then "walk" those relationships to pass relevant characteristic data (e.g., height of Tree) to the rendering engine for the actual display. To answer your specific question: I have no idea where getComposedImage should go. B-) That would require more knowledge of the requirements and problem space to be abstracted. However, as a starting point my two main points above are: (1) Take some time to partition the application into distinct subject matters that can be encapsulated behind interfaces. [The Application Partitioning category of my blog may be of some assistance for that.] (2) Separate the /structure/ of the composition from the mechanics of rendering it. Capture as much of that structure as possible in static structure like relationships. Treat defining that structure as a problem of instantiating the right objects and relationships. Once you have done those two things you can start worrying about the details of how to pass that structure to the rendering component. When defining the objects, figure out what information the rendering will require to be able to display the structure properly. That will appear as knowledge attributes of the instantiated objects. Once you have that it should be fairly straight forward to "walk" the structure and construct a series of messages to the rendering engine containing the attribute values, identity, and relationships so that it can be rendered. > PD: Sorry about my English, I am from Argentina, so it's not my > primary language. Your English is fine; better than a number of US compatriots I know. But being Argentinean is a different problem... B-)) ************* There is nothing wrong with me that could not be cured by a capful of Drano. H. S. Lahman hsl(a)pathfindermda.com Pathfinder Solutions http://www.pathfindermda.com blog: http://pathfinderpeople.blogs.com/hslahman "Model-Based Translation: The Next Step in Agile Development". Email info(a)pathfindermda.com for your copy. Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php. (888)OOA-PATH
From: andreagiorgetta on 26 Aug 2007 20:09 Responding to H. S. Lahman... First of all, Thank you so much for your response. By reading your answer, I'm absolutly sure that my explanation of the problem to solve was very very incomplete :). Even though, many of the concepts you explained are really useful, so thanks (again). First of all, we are programming in Delphi 7. Ok, Delphi is not the best language for OOP, but using it is one of our non functional requirements. Picasa is (Google's) application for organizing and cataloguing every image (maybe I should say "photos"...) in someone's hard disk(s). The idea is that you can create an album, add images to it, browse it, view its pictures and, eventually, you can do some basic editing tasks on them (rotate the image, cut and crop, adjust brightness, contrast, reduce red eye effect, etc). The component suite we use to edit images is ImageEn (www.hicomponents.com, which is probably the most powerful for image processing in Delphi, and another of our non-functional requirements). We created a class that interacts with those components, and a Facade for it. We added a Facade because we suspect that we will not use only ImageEn components, probably for some editing tasks we'll need another, so we though that we would have an "image processing subsystem" in the future (even today it has only one class), and a Facade could provide a simple interface for it. We are just starting with the development of the application, but we already have the (obvious) classes "Album" and "Photo" (Album contains photos, a user can have several albums, etc). In GUI, we use a miniature view component (ImageEnMView) which displays, for example, all the photos of an album. We had no idea where we should insert the code to update that miniature view when, for example, you select a different album... so and we added a GUI class which does those kinds of things (maybe the name of the class is not the best considering the class' responsibility...). In some part of the screen we need to show an image that represents an album. It is composed of a base image of a folder in which we insert a miniature of one of the images contained in that album (similar at what Windows does). To create that composed image, we need to get the base folder image, resize it, get other the image (from the album), resize it, apply a mask to combine both, etc. All those steps are image processing tasks, methods implemented by the class that interacts with ImageEn components, and they must be called sequentially in order to get the desired composed image of an album. So, GUI class puts the final image of an album (beautifully composed) wherever it must be on the screen, and the image processing class performs each one of the steps needed to get that image... but the question is: which class implements a method that calls those methods one after the other? Again, thank you so much. I'm going to read the Application Partitioning section of your blog (and probably other sections too, it seems to be a lot of useful information there). Best regards, Andrea Giorgetta > Your English is fine; better than a number of US compatriots I know. But > being Argentinean is a different problem... B-)) PD: It could be worse... ;)
From: H. S. Lahman on 27 Aug 2007 14:04 Responding to Andreagiorgetta... > Picasa is (Google's) application for organizing and cataloguing every > image (maybe I should say "photos"...) in someone's hard disk(s). The > idea is that you can create an album, add images to it, browse it, > view its pictures and, eventually, you can do some basic editing tasks > on them (rotate the image, cut and crop, adjust brightness, contrast, > reduce red eye effect, etc). The component suite we use to edit images > is ImageEn (www.hicomponents.com, which is probably the most powerful > for image processing in Delphi, and another of our non-functional > requirements). We created a class that interacts with those > components, and a Facade for it. We added a Facade because we suspect > that we will not use only ImageEn components, probably for some > editing tasks we'll need another, so we though that we would have an > "image processing subsystem" in the future (even today it has only one > class), and a Facade could provide a simple interface for it. OK, the Facade sounds like a good idea for exactly the reason you gave; you can substitute behind it without affecting the clients. > We are just starting with the development of the application, but we > already have the (obvious) classes "Album" and "Photo" (Album contains > photos, a user can have several albums, etc). In GUI, we use a > miniature view component (ImageEnMView) which displays, for example, > all the photos of an album. We had no idea where we should insert the > code to update that miniature view when, for example, you select a > different album... so and we added a GUI class which does those kinds of > things (maybe the name of the class is not the best considering the > class' responsibility...). OK, I misunderstood; I though the GUI object was managing the display directly (e.g., talking to an OS Window Manager). I'm not keen on the name but it seems like a good idea. B-) This sounds like the GUI object is a similar sort of Facade for the miniature view component as for the editor component above. That allows you to dynamically define the album to display: [Album] | 1 | accesses | | R1 | | current for | 1 [GUI] + displayAlbum() | 1 | | R2 | | knows how to talk to | 1 [ImageEnMView] When the user selects a particular album in the real GUI, that processing instantiates the R1 relationship. Then when it is time to actually display the album somebody invokes GUI::displayAlbum(). That method navigates the R1 relationship and does whatever it needs to do to present it to ImageEnMView. ImageEnMView may not be an object per se; displayAlbum could just invoke a predefined API. It is just convenient here to think of it conceptually at the OOA/D level as an entity. If ImageEnMView is accessed through an API, then it would essentially be external to this subsystem and the API represents a subsystem interface. If that is the case, then GUI becomes a surrogate object that represents ImageEnMView in the current subsystem by providing a convenient interface for this subsystem's context. > In some part of the screen we need to show an image that represents an > album. It is composed of a base image of a folder in which we insert a > miniature of one of the images contained in that album (similar at > what Windows does). To create that composed image, we need to get the > base folder image, resize it, get other the image (from the album), > resize it, apply a mask to combine both, etc. All those steps are > image processing tasks, methods implemented by the class that > interacts with ImageEn components, and they must be called > sequentially in order to get the desired composed image of an album. > So, GUI class puts the final image of an album (beautifully composed) > wherever it must be on the screen, and the image processing class > performs each one of the steps needed to get that image... but the > question is: which class implements a method that calls those methods > one after the other? I don't think there should be a single method that manages that sequence. That method would be equivalent to a high level node in a functional decomposition tree and we don't do that in the OO paradigm. You have described several different activities needed to get the <beautifully> composed image. Each of those should be a distinct responsibility in one or more objects. That is, each activity would be encapsulated in a method that was self-contained and logically indivisible at the subsystem level of abstraction. One would then connect the dots of individual methods with messages that form a sequence in the overall flow of control. Thus the method that gets the base folder image calls the method that resizes it once it is obtained. Then the method that resizes it either calls the method to get the next base folder image (if this is the first image) or calls the method to do the masking (if this is the last image). To do that all you need is a count of the base images to process in an attribute somewhere and you decrement it each time the resize method is invoked. Why is this better? For one thing we have reduced the iteration to a message creation that is conditional. That is, the iteration has been cast into a decision about which message to issue and where it goes. That segues to the main advantage. The flow of control is now orthogonal to the processing in the various methods. One can change the overall flow of control by simply placing the message generation in different methods. This is very important because it means one can change flow of control without touching the code that does useful work in the various methods. That limits the possibility of inserting errors during maintenance and makes changes easier in many situations. Most important of all, though, it allows one to think about flow of control at a higher level of abstraction than object methods. (In UML one can define the messages in an Interaction Diagram, which is completely separate from the method descriptions.) That allows one to apply DbC techniques to rigorously determine the correct flow of control in complex situations. Unfortunately this is not very apparent in the OOPLs because they are 3GLs and have made substantial compromises with the hardware computational models. One of those compromises is that a message is defined as a method signature in the 3GL type systems. That removes the separation of message and method. Worse, it encourages a procedural imperative view (Do This) because we name methods by what they do. In the OOA/D messages are supposed to be announcements (I'm Done) of something the sender did. If messages are announcements, then the sender implementation has no reason to depend on what some receiver may do in response. That removes the hierarchical dependencies that led to Spaghetti Code. However, if one has the proper mindset and thinks of messages as announcements, then one has a better chance of constructing methods without context dependencies. Then the marriage of message and method in the OOPLs doesn't do any harm because the methods are pure of heart. ************* There is nothing wrong with me that could not be cured by a capful of Drano. H. S. Lahman hsl(a)pathfindermda.com Pathfinder Solutions http://www.pathfindermda.com blog: http://pathfinderpeople.blogs.com/hslahman "Model-Based Translation: The Next Step in Agile Development". Email info(a)pathfindermda.com for your copy. Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php. (888)OOA-PATH
|
Pages: 1 Prev: Help in class diagram building Next: Are you using Agile methods? If so, do you model? |