< Day Day Up > |
3.11. The Spreadsheet ConundrumThe spreadsheet is an analogy for many design decisions you make during development. Consider the data on a spreadsheet, as shown in Figure 3-1. If you were to store the data in a linear manner in a file, you would need to decide whether to store the data by row or by column. Perhaps storing it by row seems most natural. What if programs that require the data in column order access it later? Row order makes that access inefficient. Figure 3-1. Spreadsheet of CDDiscs and daysIf you knew that future programs were going to use column order, you should have considered that in your initial code. However, if you cannot reasonably foretell in what order data will be accessed, you cannot worry too much now how it should be stored. Just document your assumptions and later on, if you have to change your approach, you will at least know why you did it the other way. Many facets of programs parallel the spreadsheet. For example, string resources and languages form a spreadsheet such as that shown in Figure 3-2. Figure 3-2. Spreadsheet of resources and languagesTypically the data in Figure 3-2 is stored with strings stored sequentially for each language. If you will be adding more languages, having the data stored in that manner makes sense. However, if you are always adding more resources, but never adding more languages, it could be more efficient to store the strings sequentially by resource.
This spreadsheet conundrum is reflected in the organization of graphics packages. A package can be organized in two ways, which correspond to the rows and columns of Figure 3-3. Figure 3-3. Graphics spreadsheet3.11.1. A Graphics ExampleFor example, to draw a rectangle on a device, you could write the code as shown in Example 3-1. Example 3-1. Shape drawing selfclass Rectangle draw(DeviceContext a_context); class Circle draw (DeviceContext a_context); Rectangle a_rectangle = new Rectangle(); Circle a_circle = new Circle(); a_rectangle.draw(a_device_context); a_circle.draw(a_device_context); Example 3-1 represents selecting the column headings as the shape performing the drawing. The alternative is to select the row headings to perform the drawing, as shown in Example 3-2. Example 3-2. Device drawing shapeclass DeviceContext draw(Rectangle a_rectangle); draw(Circle a_circle); DeviceContext a_device_context = new ScreenDevice(); a_device_context.draw(a_rectangle); a_device_context.draw(a_circle); In Example 3-1, it is easy to add additional drawing shapes , such as a triangle . You create a class for the new shape and implement a draw method. In Example 3-2, it is harder to create a new shape. You need to add a method to draw the shape to every implementation of the device context. 3.11.2. Who's in ChargeThe same conundrum applies to the question of "Who's in Charge." For example, you could arrange the operation of dialing a phone number as shown in Example 3-3. Example 3-3. Phone does the dialingclass Phone dial(PhoneNumber a_number) Phone a_phone = new Phone(); a_phone.dial(a_phone_number) Or you could arrange the operation as shown in Example 3-4. Example 3-4. PhoneNumber does the dialingclass PhoneNumber dial(Phone a_phone) PhoneNumber a_phone_number = new PhoneNumber(); a_phone_number.dial(a_phone); The distinction regarding who is in charge of dialing a phone number might not make any difference until you come across a situation in which you might want to send another set of digits to the phone (such as an account number): class AccountNumber IntegerString number; In Example 3-3, you would add another method to Phone. For example : class Phone dial(PhoneNumber a_number) dial(AccountNumber a_number) In Example 3-4, you would add a dial() method to the AccountNumber class to keep operations consistent with the PhoneNumber class. class AccountNumber dial(Phone a_phone); The tradeoff between these two approaches is not clear-cut . In one instance, you are asking a Phone to dial a set of digits. In the other, you are asking the object to dial itself on a Phone you provide. If you prefer one way, document your reason in your design journal. Later on, you might come across a situation in which the other approach seems more appropriate. You can review your previous decision and see whether the reasoning still makes sense in light of the new context. The spreadsheet conundrum appears in many forms, which I will note throughout this book. Recognizing when you are making a tradeoff between two ways of organizing a class structure can help you to make better design decisions. |
< Day Day Up > |