Object Definition


Semantic nets and stories (scenarios, use cases, interaction diagrams) provide input, but the most critical aspect of discovery is object definition. Each object must be identified in terms of its actual or intended use in the problem space ”the domain. The metaphor of domain anthropology continues to shape our thinking about each individual object and what we expect of it in terms of services (behaviors, responsibilities).

Each circle on the semantic net is a potential object. We can select any one of them and attempt to identify all of the services such an object might provide in its domain ” in its domain, not just the application or specific problem where we first encountered this object . It is true that object thinking is biased in that it expects most objects to have limited and simple behaviors ”which makes it possible to model them in terms of an entire domain rather than an application. This bias is supported by experience, but it is an inductive conclusion, and the exception or exceptions may yet be found. Typically we would use the first two sides of the object cube model to record our thoughts about the object and its behaviors.

Our goal during discovery is object definition, not object specification. Definition means we want to capture how the object is defined by those using it, what they think of that object, what they expect of it when they use it, and the extent to which it is similar to and different from other objects in the domain. Specification will come later (maybe 30 seconds later if you are doing XP and working on a single object), when we allow ourselves to consider how this object might be implemented (simulated) in software. Specification will involve making some design decisions and capturing the information necessary for someone to actually build the software version of the object.

Object definition involves capturing three bits of information: a short prose description of the object (in the words of a domain user ), an enumeration of the services it is expected to provide (and, if other objects are used as helpers for any given service, the kind of object to be used), and, when appropriate, a stereotype ”another object or other objects that the one we are working with resembles in terms of similarity of services provided. Wirfs-Brock and McKean identify several stereotypes, including information holder, structurer, service provider, coordinator , controller, and interfacer. Peter Coad has also written about a wide variety of stereotypes. Ivar Jacobson uses the idea of stereotypes with emphasis on model (service providers), views, and controllers.

Side 2 of the object cube is used to record the description and any stereotype; side 1 is used to record the list of responsibilities and collaborators. To this point, we are engaging in exactly the same thinking and recording process advocated by Beck and Cunningham and their CRC cards. It would not be unusual to actually use 3 — 5 index cards for discovery because they are cheap, easy to modify, and shareable (you can pass them around); and they provide a good visual reminder that well-defined objects have limited responsibilities.

Where to start? Pick an object or two from the stories selected by the customer for the first development iteration. This will provide a starting point. For example, Application and entryField . We ask the user (domain expert) for a definition, and the user responds, An application is a kind of form used to collect specific facts about the people applying for a mortgage and the home they want to purchase. We record this information on side 2 of the object cube (or on the back of the 3 — 5 card). The definition, conveniently, provides us with insight into a stereotype for the application object ”it s a kind of form. So we record that fact on side 2 as well. (See Figure 7-7.)

click to expand
Figure 7-7: Side 2 of the object cube for the Application and entryField objects contains a simple record of the description and stereotype obtained from the domain expert (user).

We do the same thing for the entryField object, obtaining the information shown in Figure 7-7.

We now turn our attention to the services we expect from our Application and entryField objects. We have several choices of how to think about the services. We can look at the arcs connecting the application circle to others on the semantic net to see whether they suggest services expected of the application. We can go over the story about filling out the application to see what was expected of the application in that story. Either of these options is likely to expose services that our application must satisfy , but those services might be couched in specific language reflective of the limited context in which we discover the service rather than the domain as a whole. We will take care to generalize any such discovery so that the service reflects the needs of all of the objects that might use our application.

A third way to approach the enumeration of services is simply to ask the question, I am an application; what services can I provide to others? To help us answer this question, we can look at an actual physical example of the application form, and we can begin to collect those stories involving the application that have been provided to guide our immediate development activities and phrase the question in the context of each of those stories. In this story, what services do the other objects expect of me? As your project evolves and as the application object is discovered in other projects with other stories, you revisit your thinking about the essential services that your object is to provide.

We notice that the application has a funny string of characters at the bottom (something like AF001rev10/03), and we also notice a line of print at the top in larger font size than the other contents. We surmise that these character strings identify the form in some way. We also recall that the stories told about the application implied that users of the application looked at it to confirm that they had the right form. From this we conclude that the form has a responsibility to identify itself . We record this information on side 1.

Visual inspection reveals several examples of short text strings and several examples of blank spaces. We might give these things names ” textString and entryField , respectively ”and then create a new object cube with those names on them. We will want to explore those objects later to determine what their responsibilities might be.

Our attention is on the application, however, so we wonder whether the application has any responsibility in connection with these newly discovered objects. It s obvious that the application holds these elements in an organized manner. We might arrive at a responsibility that the application holds elements. We reject the phrasing holds elements because that does not describe a service; instead, it describes something the application must do to provide a service. If we say holds objects , we are implying an implementation decision: how an object is to do something rather than what it is to do. A bit of thought, and we come up with the responsibility provide access to elements . Implicit within this responsibility are variations such as provide access to a subset of elements and provide sequential access to elements . We might record these variations on side 1 so that we don t forget them, even though we aren t sure they are appropriate responsibilities.

Note  

Abstraction, generalization, classification, and essentialism are three quite different but apparently similar concepts. Abstraction is the act of separating characteristics into the relevant and irrelevant to facilitate focusing on the relevant without distraction or undue complexity. Generalization also involves separation but more in terms of shared and not shared characteristics. Classification involves (depending on the linguistic theory you prefer) either separation based on conformance to a set definition or similarity to a prototype ”the separation being in the class or not. Essentialism is an attempt to separate accident and essence ” to identify the characteristic that is essential to being considered an instance of some class.

Unfortunately, abstraction and generalization tend to be used as synonyms for all four terms as well as for each other. I am as guilty of this as anyone else ”hence this note and its attempt to deal with an apparent contradiction between object thinking and XP.

Kent Beck says, Keep things simple by not providing abstractions until the abstractions provide simplicity, one expression of his consistent warning against premature abstractions. He, and most followers of XP practice, believe that abstraction should arise from refactoring rather than from activities typically associated with the analysis and design phases of traditional development.

Object thinking suggests you should take care to generalize responsibilities so that they can be used in any context. This is not abstraction of the type chastised by XP. It is much closer to essentialism ”finding the specific traits or characteristics that make a thing a thing. Sometimes this is as simple as removing adjectives from a service description (method name ). At other times, it is subtler and a bit closer to generalization: instead of Provide unique identification number as a responsibility that reflects how an object identifies itself in a context, use Identify self. A significant part of object thinking is devoted to providing the philosophy and metaphors and definitions required to accomplish this paring of things to their essential nature. I believe that the apparent contradiction between object thinking and XP is just that ”apparent ”and derives from nuanced use of common terms.

We can see the application, so we know it can display itself. We would record display itself on side 1. It s necessary to think a bit about what s involved in displaying the application because more than one object is visible: the application, of course, but also the textString and entryField objects. It s inappropriate for one object to assume responsibility for the actions or behaviors of others. The text strings and entry fields must display themselves . The application might be the recipient of the display request, but it must be careful to delegate some of the display behavior to its elements. We can capture this information by recording that myElements is the collaborator used by the application to make sure all objects are displayed.

Note  

As you tackle more stories involving forms, you ll discover additional abstractions or recursive use of the same abstractions. For example, a complex form might have sections or pages that are themselves forms with their own elements ”an example of recursive organization. This kind of organization reflects the composite pattern. Some forms will have check boxes or other means of collecting information. At first, these appear to be something other than an entryField , which in our discussion so far appears to be a box for collecting a string. A bit of reflection reveals that a check box ”and almost any other widget you might find of use in simulating a form ”is, in terms of its behavior, just an entryField . Different widgets have different appearances , and thinking about that fact might lead you to positing a view object, charged with providing a visual presentation of an object. An object that exists in different view contexts would have multiple view objects at its disposal, one for each context. An apparently simple responsibility of the form object ”display itself ”turns out to be quite complex when we start to think about writing the code that enables that responsibility. But we want simple code as well as simple responsibilities. To obtain simple code, we must refactor ”which means thinking about how we can break up the code and distribute it to other objects. In this case, part of the responsibility gets delegated to the elements that the form comprises and still further to objects that specialize in visual representation tasks ”view objects.

Usually we want to record only one collaborator on a line. To accomplish this heuristic goal, we might stereotype both textString and entryField as displayable objects. We can then record displayableObject as the collaborator. It would be nice to be a bit more specific about instances of displayableObject that we are collaborating with, so we might refine our label (which identifies a new class to be thought about) to displayableElement instead. This implies that any elements the application contains that are displayable are the ones we collaborate with to complete the application s display responsibility.

The fact that the application is a container of other objects also suggests to us  a second stereotype for application. It has behaviors similar to a collection ”another type of container object. We should add this observation to side 2 of our card.

One more responsibility needs to be considered. In one of our stories, it was suggested that the application form needs to be verified or validated . The information entered on the form ”the information contained within the entryField objects ”must be confirmed. This would suggest a responsibility validate application form . But who should this responsibility be assigned to? According to the precepts of object thinking, the application must be responsible for validating itself!

So we add one more responsibility to side 1 of the object cube, validate self . Exactly how this is done we do not know. But a bit of reflection indicates that part of the validation is done on the values stored in each entryField . The application should not be validating the entryField; the entryField must be responsible for that itself. Just as was done with the display responsibility, the application will delegate to each entryField its share of the validation workload. We list entryField as a collaborator for the validate self responsibility of the application.

Alas, our thinking may be leading us astray a bit in our consideration of validation. Perhaps it is not one task but two similar tasks, one of which belongs to the application and the other to the entryField . To be sure we are doing the right thing, we need to ask what is meant by validation as that term is used in the domain. So we might ask a user, How is an application validated? The user then provides a simple story about validation:

Well, the data in each field is checked to see whether it s the right kind: a name, a date, a dollar figure, things like that. Then we verify that the value is accurate and permissible. By permissible we mean things such as the number entered in age has to be between 25 and 40, or the number of years married must be between 2 and 10. By accurate, we mean that the income figure is verified with the employer. Also, the bank balances , things like that. Finally, we check the application for consistency. Say they enter a city name and a postal code. We check to see that the postal code matches the city.

Thinking about the story suggests that the application, as well as each entryField , is validated by applying a rule or rules to the value stored in an entryField . In the case of the application, the rule might have to look at values stored in more than one entryField .

Our first attempt to implement this story might utilize a lot of If statements and the hard-coding of a lot of values in the conditional checks of those If statements. There is significant potential for inappropriate coupling of our objects ”for example, if we had a validate method for a form with code that looked like the following:

 Validate Ifform.cityconcatenatedwithform.zipisfoundinzipcodeDirectoryreturn "TRUE"Elsereturn "FALSE." 

If the names of fields on the form change or if the rule changes in some fashion, we will have to fix the code. There is insufficient flexibility and too much reliance on conditional code to pass the XP smell test. Applying the object thinking principle ”everything is an object ”in thinking about how to refactor our code should lead to the discovery of another kind of object ”a rule object. A rule object is given the responsibility to evaluate itself to some value (either the TRUE or FALSE of this example or any other value). We can then provide the form and each of its entryField objects with a rule (or rules) that it can use to effect its own validation. So we change both object cubes to reflect the newly identified collaborator. We would also make a new object cube for the validationRule object.

When we are done, we probably have the object cube ”sides 1 and 2 ”for Application and for entryField completed as shown in Figure 7-8. Once we complete sides 1 and 2 of an object cube for every object identified in our semantic net, and once we have assured ourselves that we can tell any story the user can tell us about using those objects, we are done. The overall result for the subsidized mortgage company will be similar to Figure 7-9 (side 1) and Figure 7-10 (side 2).

click to expand
Figure 7-8: Sides 1 and 2 of the Application and entryField object cubes. "(Indented lines on side 1 of Class: Application are collaborators for the immediately preceeding responsibility.)"
click to expand
Figure 7-9: Objects identified in the subsidized mortgage example (side 1 of the object cubes).
click to expand
Figure 7-10: Objects identified in the subsidized mortgage example (side 2 of the object cubes).

As you look at the figures, you ll see objects that we have yet to discuss in the text ”objects that have come to light as other developers worked on their stories. As the team works, objects will be proposed and developed by different pairs, and you might not be aware of much more than the names of the objects until you have the opportunity to work on a story involving those objects.

Object discovery provides us with a set of named objects and a set of responsibilities assigned to each one. We might also have a short prose description of the object and a stereotype. In one sense, we are ready to code the objects we have discovered, and that would be the expected activity of the XP programming pair (coding tests first, of course).

Object thinking can still help you as you think about the code and start to make implementation decisions. For example, we can use the stereotype to suggest an existing object that might be modified or employed to help fulfill the responsibilities of the one we are working on. This kind of implementation decision will give rise to a taxonomy of classes ”a class hierarchy. Such a hierarchy has several benefits for programmers: providing already written and tested code that we can employ for our own ends and, because of the taxonomic organization, a kind of index we can use to look for code that might be useful to us.

Chapter 8 will introduce some additional aspects of objects that we can think about to facilitate our implementation ”aspects that might be characterized as design considerations. In Chapter 10, we ll look at class hierarchies (taxonomies) in a bit more detail.

start sidebar
Another Example ”Some Objects from an Air Traffic Control (ATC) System

Imagine we are working on modeling the world of air traffic control. We will have identified a number of objects in that realm, including passengers, airplanes, control towers , flight routes, controlled airspaces, and many more. We will also have captured a number of stories about how objects interact in this world. The following is a brief illustration of how a few objects might have been modeled in such an example. We will focus on the airplane and some objects that come to be identified as we consider the airplane and its responsibilities. We will use the story of how an airplane fulfills one of its responsibilities ”reporting its location as the background ”for our process of discovery.

Figure 7-11 includes a depiction of side 1 of the object cube for an airplane. By identify self , we mean that the plane can provide its registration number. Describe self entails giving a requester of that service an object containing the characteristics of the airplane (type, manufacturer, seating capacity, and so on). Report location means the airplane will provide a location object containing all the pertinent information for a location (altitude, latitude, longitude, vector, and so forth). Move to new location means the airplane will actually relocate itself in space.

click to expand
Figure 7-11: Side 1 for airplane, location, instrumentCluster , and instrument objects.

The only one of these responsibilities that looks complicated to code is move to new location. A fair amount of calculation is required to determine the combination of acceleration and attitude that will be required to get from here to there, and then directives need to be issued to the objects capable of effectuating those changes.

There is another, subtler, complexity in the plane s ability to report its  current location. Although the explicit responsibility is to provide a current location, there is an implicit responsibility to report the correct current location. A location is a composite of several values ”all of which are dynamic ”and the only way that the plane can assure itself of the correctness of the location it is providing is to have one constructed in response to the request it receives from the control tower.

We probably do not want to add a responsibility to the airplane of the sort , construct location . Instead we acknowledge the need for construction in the original report current location responsibility by adding a collaborator to that line. We then expect the collaborator to assume the task of construction. Object thinking mandates that objects do things to themselves, so the obvious collaborator is a location object.

The airplane can ask its collaborator, the aLocation object, to instantiate itself (obtain and remember all the appropriate values for altitude, latitude, longitude, airspeed, and so forth) immediately upon receiving the control tower s request for a location. The location object then interrogates the necessary instruments to get the values it needs. But which instruments? How does (or how can) the location object find the instruments it needs to instantiate itself?

The airplane provides the context for the request, so we want to interrogate the instruments associated with (that are a part of) the airplane; therefore, we ask the plane for those instruments. The location could ask the plane for each instrument in turn, but our code will quickly reveal this to be a less than optimal design. For one thing, the plane is busy, and we would be an annoying disruption. For another, we would have to add a lot of responsibilities to the airplane of the sort, provide access to altimeter . Instead of creating a provide access to responsibility for each instrument, we introduce yet another object ”an instrumentCluster ” and add a provide access to instrumentCluster responsibility to the airplane.

An instrumentCluster is basically a collection of instruments. As with any collection, we can ask it for a subset of its members and ask it to iterate across its membership. The location can then ask the instrumentCluster for the next instrument in the collection and ask that instrument for its value.

Remember, the thinking and design activities that we just discussed take place as part of the activity of writing tests and code. It need not be an explicit separate step in the development process. It s reflective of the thinking that goes on as each pair interprets their story, identifies the objects needed, thinks about which object will do what, and how that object will actually do what it is expected to do.

If the development team chose to actually draw models to assist them in this chain of thought, they might look at Figure 7-11 (side 1 of the object cubes for Airplane , aLocation , instrumentCluster , and Instrument ) and Figure 7-12 (an interaction diagram confirming the report current location story).

click to expand
Figure 7-12: Object communications required for an airplane to tell the control tower where it is currently located.
end sidebar
 

Heuristics

Implicit but perhaps not obvious in the preceding section (and in the sidebar) are a number of heuristics for discovering and assigning object responsibilities. There are also some points where the developers thought processes might have proceeded in a different direction: there are different and equally valid object designs. Some hints of why the examples shown are as they are can be incorporated into the discussion of the heuristics.

Heuristic: Let objects assume responsibility for tasks that are wholly or completely delegated to other objects in cases in which the responsibility reflects natural communication patterns in the domain.

For example, the question might arise as to why the control tower asks the airplane for a location instead of talking directly to a location object and having it talk to the airplane s instrument cluster. After all, it is the location that actually does the work. If you are familiar with modern aviation, you know that control towers have the ability to talk to at least one instrument carried by an airplane ”the transponder . This question raises a general issue of when an object should or can assume responsibility for work actually done by others.

In the case of Airplane , it seemed a natural call. After all, the control tower already has to talk to the planes (actually the pilots) about all manners of business, so it doesn t seem illogical for it to do so for location as well. The plane is already visible to the control tower, and the plane provides the context of meaning for the values that will be accumulated by the location object. It does no harm to let the plane front for location, and it does a lot of good. Similarly, there is value in letting the location object front for the instrumentCluster and Instrument objects. If at some point in the future we have a more abstract FlyingThing , we can use the same interface to obtain locations for any specializations of that class, such as the airplane. If the definition of location (the type and number of values it contains) varies, the interface remains the same. If new types of instruments are invented, they can be added to the instrumentCluster without any need to know details about them ”as long as they can respond to the currentValue message.

Heuristic: Delegate responsibilities to get a better distribution and increase reusability.

An example of this heuristic arises from the answer to the question of why the Airplane needs the instrument cluster. We can arrive at the answer by enumerating all the responsibilities that are involved with keeping track of and using a set of instruments:

  • Know which instruments are included in the set.

  • Assemble a location by asking the correct instruments, in the correct order for their values.

  • Remove an instrument from the set if it is bad.

  • Keep track of which instruments belong in which kind of airplane.

  • Add new instruments when available.

  • Monitor the status of all the instruments.

  • Replace an instrument with an improved model when asked.

  • Make one or more instruments available when asked.

This seems like a lot of work for an airplane to undertake, especially when we would like the airplane to concentrate on moving safely from one place to another. Safe flying requires a lot of responsibilities in its own right, responsibilities quite dissimilar to those just enumerated. It will also increase reusability of both the airplane and instrument cluster objects by keeping separable responsibilities separate.

When an object accepts responsibility for work that it cannot do alone, it does so to meet expectations expressed in its environment. As the programmers write the tests and code for that kind of responsibility, each segment of code represents their thinking about specific tasks that the object must complete if it is to accomplish what is expected. Each of those tasks ”code segments ”might be moved (via refactoring) to other objects better prepared or better suited to fulfilling that specific task. Delegation arises from refactoring code. But it s expected that programmers learn from experience and that the next time you think about a test or a block of code, you might recognize immediately that it belongs in a different object ”a kind of anticipatory refactoring that is grounded in your own programming experience.

Delegation can lead to the temptation of management. This is to be avoided. If you delegate, delegate. Do not try to retain any control over how your delegate does its job. Do not attempt to second-guess your delegate s work by adding all kinds of elaborate result-checking code. When you actually code the delegate object, give it the ability to evaluate its own work and correct its own mistakes, and then rely on it to do its job while you concentrate on yours.

Heuristic: Use anthropomorphization and foreshadowing to determine whether an object should assume a given responsibility.

Experience doing object development allows you to anticipate (or at least think about) what might happen as a guide for current activities. Foreshadowing is a necessary part of iterative development. It allows you to learn from prior experience and apply that learning to avoid doing wasteful or inappropriate things right now. The future you anticipate might be the next test, the next line of code, the next object or task in the story you are working on, or even the next story.

Foreshadowing will frequently take the form, If I give this object this responsibility, later I will find that it requires this and this piece of information and will require an ability to do this thing in this manner. You can then decide that the responsibility should or should not, in whole or part, be assigned to the object under consideration. If your immediate thinking about a method seems to be leading you in the direction of constructing a complicated and long method, stop! Think ahead a bit and reevaluate what you are doing. There is no need to write ugly methods if a bit of foreshadowing can help you refactor as you write. Decisions regarding responsibility assignment and method code are seldom final; they are just a way to help you distribute responsibilities in a way that minimizes, to some degree, future work.

Foreshadowing is not a substitute for refactoring and emergence; rather, it s a way to learn from experience and to apply XP and object thinking principles as you work. For example, as you start writing the twentieth line of code for the method you are currently working on, you should be hearing alarms ” This is too hard ”that cause you to pause and see whether you can mentally imagine what the entire method will look like and refactor the image of the code instead of the actual code.

Anthropomorphization assists us in thinking about responsibilities and other objects in several ways. We can think of objects as being lazy and wanting to do only a limited and closely related set of activities. We find the responsibilities that need to be delegated to other objects by foreshadowing what might be involved in fulfilling a responsibility. We can think about how much the object might need to know, whether it will need to know the wrong kinds of things about other objects (that is, anything not evident in the object s interface), and what it might need to do.

Heuristic: Responsibilities should be distributed among the community of objects in a balanced manner.

No object should have a disproportionate share of the responsibilities. How is it determined whether an object has too many or too few responsibilities? If you use a 3 — 5 lined index card to record your responsibilities ”one to a line ”you will find you are limited to six or seven entries. This is an excellent heuristic for the maximum number of responsibilities that an object can or should assume. The lower bound is that an object must have at least one unique responsibility, or there is no justification for making it a separate kind of object.

A balanced distribution of responsibilities across a group of objects is the goal. Also implied is a balance in the distribution of knowledge among those objects. An object should not do too much or know too much. You can determine the knowledge distribution, roughly , via foreshadowing, as previously noted.

Heuristic: Always state responsibilities in an active voice describing a service to be performed.

A common tendency for new object developers is to list as responsibilities things that an object must know. An airplane must know its current location. While this may be true, it can be misleading. It implies too much about how the object might be implemented because knows implies an instance variable. It s also quite possible that an object will know things (a private key for decryption, perhaps) that it will not be willing to share with others and that therefore will not be included in the interface for that object. Provide private key would not appear as a service, although the message privateKey might be in the object s protocol with the designation that it is a private message. Decrypt message , on the other hand, might be a listed responsibility. Always state your responsibilities in terms of a service, with an awareness of a possible client for that service.

Heuristic: Avoid responsibilities that are characteristic specific, that focus on providing a potential user with the value of a single characteristic of the object.

It would be a mistake to list responsibilities such as know age, know height, know eye color, and know weight. (See the preceding heuristic.) It s also a mistake to list report age, report height, report eye color , report weight. Even though the latter are in an active voice, they are characteristic specific and should be avoided. The source of the problem is that an object might have a lot of characteristics, and you have room for only six responsibilities. It s better to look for an umbrella label for the responsibility, such as describe yourself or identify yourself . Important advantages will be gained by following this heuristic, that is, keeping the conversation at the right level: what, not how or how much.

Note  

As a developer, you try to get basic behavior first. Obviously, when you get to the details, the actual details will be necessary, but not now. For example, you might have a responsibility called describe yourself or provide access to demographic information . You might ask the on-site customer a couple of questions:

When you say ˜demographic information, do you mean name, address, phone number, and so on? Yes, she might reply, that, and hair color, eye color, and the like.

Are they all used just for informational purposes, or are some of them prominent in other behavior?

They are mostly informational, except , an answer that may lead to a new responsibility or a natural grouping.

Sometimes you get domain people who want you to know every characteristic. Assure them that you ll get the complete list when we are getting ready to implement this behavior.

One advantage is flexibility. If you make the interface to your class dependent on the characteristics it might need to report and someone decides on a new characteristic, you will need to redefine your class. The alternative is to have a responsibility describe yourself , which results in giving the requester a description object. This description object might be a simple collection of key/value pairs or an arbitrarily complex object with its own domain-driven (not just this story) set of behaviors. Even the simplest case provides significant flexibility. The description object can be asked for one or more of the values it contains so that the client gets the information it needs. However, when you decide to add a new characteristic to an object, you can do so by simply sending a message to its description object telling it to add a key/value pair reflecting the new trait. (Again, assuming a very simple form of description object.) No redefinition or recompilation is required.

Foreshadowing implementation for a moment reveals another advantage arising from the fact that different clients might need to ask about different characteristics. If the characteristics are defined in the interface, a situation requiring multiple object types (classes) is created. For example, it s likely that a credit department will need to know characteristics of customers that are not shared by other departments in a company. The temptation, when characteristics are part of the interface (or when a data-driven approach to design is used), is to create a small class hierarchy with Customer , CashCustomer , and CreditCustomer , with Customer defining common characteristics as attributes and CashCustomer / CreditCustomer adding at least one unique attribute each.

If the characteristics of a customer are held in a description object, only the Customer class is needed. All clients can ask the customer for its description and then ask the description for those characteristic values in which it s interested. Cash or credit becomes just an additional characteristic of the object, not a determinant of class structure or other implementation details.

There are some obvious exceptions to this heuristic. Almost all objects will need to identify themselves on occasion. The object returned when the ID please message is sent might vary significantly from object to object: the object might be as simple as a string or as complex as a passport. Depending on the context, both types of identification object might be required. It s quite likely that if a simple identity string is a characteristic of the object, that same string will likely be part of the more complex object, the passport. Deciding whether a characteristic merits a separate responsibility will be revealed in the collection of scenarios in which the object is involved. If an object has 10 characteristics, for instance, and 1 of them is asked about frequently and by a number of clients, it should probably be a separate responsibility. If the other 9 are the subject of only occasional inquiries or are almost always asked for at the same time and in the same circumstances, they should be grouped in some fashion, and the responsibility becomes to return the group.

Heuristic: Create proxies for objects outside your domain that are sources of information required by objects within your domain.

In the process of completing both the binary use cases and the scenarios, a number of objects that are outside your domain will be identified. Legacy systems and human beings are the most obvious examples. They continue to be of interest and importance because they are sources of information or behavior that your objects will require. These requirements will be exposed in the scenarios as messages sent to these outside objects.

Note  

Some objects that appear frequently in your stories may turn out, in fact, to be external objects or representatives of external objects. For example, the airplane object in the air traffic control example earlier in this chapter is really a kind of proxy for objects that are not directly part of the ATC system itself. Real airplanes (their pilots, really) are customers of the ATC and a source of information that the ATC uses in fulfilling its responsibilities.

For instance, if I were an order object I might need to obtain information and decisions from a human being. I will want them to describe themselves to me and tell me where they live, and what items from our inventory they want. Since you cannot build a human being object, you can create a HumanInformationInterface object or a HumanProxy object that will be your interface to the real-world human. A generalization of this heuristic is a class DataSourceInterface , of which HumanProxy is an instance. So common is the need for this heuristic that there is actually a pattern ”Proxy ”that documents its structure and use.

Heuristic: Look for components .

A component will look exactly like an object at this stage of development; that is, it will have a name and a set of responsibilities. When you foreshadow those responsibilities, however, the object starts to look complicated and will seem to need a lot of collaborators, usually a sign of a need for further decomposition and redistribution of factored responsibilities.

If the set of responsibilities are strongly coherent and if domain experts seem aware of but unconcerned by an internal complexity ”the way people are aware that an automobile has a complex internal nature but ignore that in favor of using a car as a car ”you probably have a potential component. You should identify your object as a component and plan to do detailed analysis of it later, as if it were a small, separate piece of application software.




Microsoft Object Thinking
Object Thinking (DV-Microsoft Professional)
ISBN: 0735619654
EAN: 2147483647
Year: 2004
Pages: 88
Authors: David West

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net