Practical Software Engineering
Moving From Design to Code
|Table of Contents|
The processes of analysis and design results in the creation and subsequent refinement of several
artifacts or deliverables. The following table shows when specific artifacts are created and when
subsequent revision occurs:
When a system is being implemented, the artifacts are used in the following ways:
The artifacts of the system contain a large amount of information and many developers feel
somewhat overwhelmed when confronted with this information. This section outlines a
standard "plan of attack" which can be used when implementing a system. This plan can
be easily adapted for differing contexts.
All object oriented languages support the definition of classes. This includes the ability to define attributes and methods. Developers should begin implementation by implementing the structure contained in the Class diagram. The Class Diagram defines all of the classes which must be implemented. If the design is sufficiently complete, the classes in the class diagram will contain attributes and method signatures. The programmer must provide a mapping between the class structure and the implementation. For simple class and method structures, many developers employ the use of code generators. Essentially, these tools reduce the amount of typing that has to be done to define the class structure for the system.
Although code generators can save a lot of time, be mindful of their limitations. Depending on the generator, the resulting code may be more or less maintainable depending on the complexity of the coding structures that are being generated. Regardless of how the code is created, humans will always have to maintain the code at some point. Avoid code generators which create incomprehensible code. The following outlines the mapping of a Class to Code:
Figure 1: Class Diagram with uni-directional association
Code Snippet 1:
public class Driver
Implementing classes from a Class diagram is relatively straight forward. The attributes have
defined types and the skeleton methods have parameter lists with defined types. Some methods
are simple enough that their bodies can even be implemented by code generators. The implementation
of associations, however, can become more difficult because of two factors:
NavigabilityAll object oriented languages support some form of uni-directional assocation. Smalltalk and Java provides support for associations through object references, Objective-C provides support for associations through object pointers, and C++ provides support through pointers and references. No language, however, provides direct support for bi-directional associations. Bi-directional associations must be implemented as two uni-directional associations.
Navigability is shown on the class diagram by placing an arrowhead on the association which indicates the direction of association. An association on the class diagram which contains no arrowheads is assumed to be a bidirectional association.
Bi-directional associations not only require more references, but they are more costly to maintain. Specifically, when an bi-directional association is made between two objects, that requires maintaining two references (not just one). These associations must remain consistent with each other and when multiplicity is involved, that can increase the complexity considerably (See below). Because of the added complexity of bi-directional associations, they should be avoided if at all possible. When performing a design review, examine bi-directional associations for justification. The reason for having a bi-directional association is because objects on each side of the association have to be able to initiate messages to objects on the other side of the association. Often, the design can be examined and an alternate method of sending messages (possibly through another existing association) can be found; thus, eliminating the need for the bi-directional association.
The following illustrates the implementation of the Car and Driver classes with a bi-directional association. Note that the implementation must now ensure the integrity of the bidirectional association.
Figure 2: Class Diagram with bi-directional association.
Code Snippet 2:
public class Driver
The simplest form of multiplicity to implement is One-To-One. The examples above show the implementation of both uni-directional and bi-directional one-to-one associations.
Multiplicity becomes more difficult when implementing one-to-many and many-to-many associations. The complexity becomes even greater if those associations are bi-directional (again, another reason to avoid bi-directional associations).
Take the example of the CarManager objects which manages several car objects. The class diagram shows that there is a one-to-many relationship between the CarManager and the Cars that it manages.
Figure 3: CarManager and Car -- Class Diagram
The question is, who maintains the references to all of the car objects? If that functionality is added to the CarManager class the added responsibilities will reduce the cohesion of that Class. To best solution is to introduce another object which claims the responsibility of maintaining the car object references. These types of objects are called Collection objects and almost all object-oriented languages provide some collection classes.
Collection classes do not typically appear on the class diagram. Their use is implied through the definition of multiplicity. Whenever there is a to-many relationship, the to-many portion will be implemented using a collection object. The developer must make the decision of which collection class to use.
The following table shows the types of standard collection classes available in most object-oriented languages:
Figure 4 shows an object model for the class diagram shown in figure 3. You'll notice that the CarManager object has a reference to an ArrayList object and the ArrayList object is responsible for maintaining the list of cars. Code snippet 3 shows a partial implementation of the CarManager Class. The CarManager delegates the management of the car references to the ArrayList object. In this specific case, the navigability between the CarManager and Car classes is uni-directional; the Car objects need not maintain a reference to the CarManager object.
Figure 4: Object model of classes shown in Figure 3.
Code Snippet 3:
Bi-directional Many-to-Many relationshipsThe most difficult and complex relationships to implement are bi-directional many-to-many relationships. There are two main forms for implementing these relationships:
Figure 5: Bi-directional many-to-many relationship.
Using collection objects
This section will show the implementation of the enrollment of students in courses using standard collection classes. In this case, each student can enroll in more than one course. Therefore, each student object maintains a reference to a collection object which maintains references to the courses within which the student is enrolled. Similarly, each course has multiple students enrolled. Therefore, each course object maintains a reference to a collection object which maintains references to the students which are enrolled within it. Figure 6 attempts to show the object model. Because of the number of associations being maintained (each object maintains multiple references to other objects through collection objects) the object structure is very complex and it is difficult to maintain. Even in this simple case of three students and two courses the object structure is complicated.
There is also a problem with this design. When the student completes the course, where is the grade stored? The benefit of this structure is that information about the relationships is easy to obtain. For example, if you wish to obtain a list of students enrolled in a specific course, simply ask the course object for its list of enrolled students. If you want to obtain a list of all of the courses that a student is enrolled in, simply ask the student object for its list of enrollments. Code snippet 4 shows a partial implementation of this model
Figure 6: Bi-directional many-to-many relationship using collections.
Code Snippet 4:
public class Course
Using association objects
Association objects are similar to association tables in a relational database. Rather than each of the Student and Course objects attempting to maintain one-to-many relationships, an object is created which maintains references to each side of the many-to-many list. Figure 7 illustrates the class model for this implementation and Figure 8 illustrates the object model. Code snippet 5 shows a partial implementation of the Assocation class Enrollment.
Figure 7: Association class managing student enrollment in courses
Figure 8: The object model for the classes defined in figure 5
Code Snippet 5:
public class Enrollment