Class Diagrams

Class Diagrams

Although the use case diagrams provide a useful way to express what capabilities the system will have for various actors, they do little to explain the inner workings of the software. This is the point at which you can start using the other UML diagrams, and your knowledge of objects, to define those inner workings in more detail.

Modeling the Domain

After the interviews with the client are complete and the use cases have been finalized, you can move on to the process of designing the software to model the domain. One thing that means is developing the system so that its classes are closely modeled after what they represent in real life. For example, in our application, users can see information about different types of musicians, so it's probably a good idea to have a Musician class, or even better, a Musician interface that all different types of musicians can implement.

Class diagrams are probably the most important diagrams to use and understand. They provide a good balance of detail and flexibility. They provide a description of the domain you're modeling, and allow a varying level of detail from very high level to very specific about the exact methods and properties of a class. In addition, they're useful to describe interesting object-oriented concepts such as design patterns, which are covered in Chapter 4.

The basics of a class diagram are shown in Figure 2-5. The top box in the rectangle shows the name of the class. The middle box shows its attributes and the bottom box shows its operations. In PHP, the terms "attributes'' and "operations'' translate to member variables and methods, respectively, in our Musician class.

Figure 2-5

The attribute types are indicated after the colon. In this simple example, all our attribute types are strings. The minus sign says that the attributes are private members of the class. The plus sign in front of the operations indicates that they are public. If an operation returns a value, its type is shown after the colon. Again, in this example they are all strings.

The following is the PHP code for Musician shown in the class diagram:

   class Musician {      private $last;      private $first;      private $bandName;      private $type;      function __construct($last, $first, $musicianType) {             $this->last = $last;             $this->first = $first;             $this->mtype = $musicianType;      }      public function getName() {             echo $this->first . $this->last;      }      public function getBand() {             echo $this->bandName;      }      public function getMusicanType() {             echo $this->type;      }      public function setName($first, $last) {             $this->first = $first;             $this->last = $last;      }      public function setBand($bandName) {             $this->bandName = $bandName;      }      public function setMusicanType($musicianType) {             $this->type = $musicianType;      }    } 


If your application had only one class, it might not be particularly helpful to draw diagrams. Because the BandSpy system will require more than one, you need to think about how the objects will interact with each other. In the previous example, we used strings as the data type for all our member variables. Generally, this is not a good idea. If a musician were a part of a band, it would make sense that you would want more than just the name of the band. You might want, for instance, the other members of the band, what genre of music they play, and so on. This type of thinking will guide you during the design phase of your software. Certain member variables will require a higher degree of complexity and therefore need to be broken out into their own classes.


Taking a look at Figure 2-6, you can see the bandName attribute moved over into an attribute of the Band class. Also note that we're not showing every attribute and method in the classes.

Figure 2-6


When using class diagrams, you need to show only what is important in the context of the diagram. Simple accessor methods for private member variables are assumed and hence left out. When a class diagram is incomplete, you can use an ellipsis (...)to show that certain information is intentionally left out.

The line connecting the two classes is a type of relationship known as an association. For this example, the association is one-to-many one Band may have many Musicians, or conversely, many Musicians can be in one Band, as denoted by the * and 1 beneath the association.

The association line can also show navigability. In our example, the line without any arrowheads shows that you can move in both directions, also known as bi-directional navigability. In other words, each class has an internal reference to the other one. If the association allows you to navigate in only one direction, it is referred to as unidirectional navigability. Figure 2-7 shows the relationship between the Musician class and the Instrument class. The Musician class has access to any Instruments in its internal collection, but the Instrument is not aware of which Musician possesses it.

Figure 2-7

Realizations and Generalizations

We mentioned previously that creating a Musician interface that all other musician type classes could implement would be a better idea. This way you can derive other classes, such as Guitarist and Drummer, that follow the rules of how Musician behaves in your system. As long as you follow the contract of the Musician interface, you can have confidence that your derived classes will play along correctly.

When you want to indicate an interface and the classes that implement it, you show a relationship between them called a realization. A dashed line shows a realization with a hollow arrowhead at the end point to the interface. Interfaces in UML diagrams are similar to standard class diagrams but are shown using the word interface in guillemots above the interface name. Figure 2-8 displays two classes, and Guitarist, implementing the Musician interface.

Figure 2-8

When you want to indicate inheritance from either an abstract class or from another concrete one, you can use a generalization. A generalization is identical to a realization except that the line is not dashed. The diagram shows the subclassing of Guitarist to create the RockGuitarist and ClassicalGuitarist classes.


Often, the useful relationships of classes are not based on associations or inheritance but rather on the way classes are grouped. Consider the example of a drum set. In our application, the Instrument interface is implemented in a concrete class such as Guitar or Piano, as shown in Figure 2-9. In addition, the DrumSet, Drum, and Cymbal classes implement it as well. The new notation of the lines with the black diamonds indicates that the DrumSet is a composite of Drum and Cymbal classes. One instance of DrumSet will contain instances of the Drum and Cymbal classes. A composite is a strict relationship characterized by two things. First, the parts of a composite may not be shared elsewhere. In other words, an instance of Drum belonging to an instance of DrumSet may not belong to any other DrumSet. The second rule is that when an instance of DrumSet is deleted, its composite parts should also be deleted.

Figure 2-9

A more general type of composite is called an aggregate. The notation for an aggregate is the same as a composite, except that the diamond is hollow. Aggregates are allowed to share instances of other classes and therefore are not required to delete them when they themselves are deleted.


Now that you've covered the basics of class diagrams, take a look at a bit of sample code based on some of the concepts you just read about:

   <?php      interface Band {         public function getName();         public function getGenre();         public function addMusician();         public function getMusicians();      }      interface Musician {         public function addInstrument();         public function getInstruments();         public function assignToBand();         public function getMusicianType();      }      interface Instrument {         public function getName();         public function getCategory();      }      class Guitarist implements Musician {        private $last;        private $first;        private $musicianType;        private $instruments;        private $bandReference;        function __construct($first, $last) {           $this->last = $last;           $this->first = $first;           $this->instruments = array();           $this->musicianType = "guitarist";        }        public function getName() {          return $this->first . " ". $this->last;        }        public function addInstrument(Instrument $instrument) {           array_push($this->instruments, $instrument);        }        public function getInstruments() {           return $this->instruments;        }        public function getBand() {           return $this->$bandReference;        }        public function assignToBand(Band $band) {          $this->$bandReference = $band;        }        public function getMusicianType() {           return $this->musicianType;        }        public function setMusicianType($musicianType) {          $this->musicianType = $musicianType;        }      }      class LeadGuitarist extends Guitarist {        function __construct($last, $first) {               parent::__construct($last, $first);               $this->setMusicianType("lead guitarist");        }      }      class RockBand implements Band {        private $bandName;        private $bandGenre;        private $musicians;        function __construct($bandName) {           $this->bandName = $bandName;           $this->musicians = array();           $this->bandGenre = "rock";        }        public function getName() {           return $this->bandName;        }        public function getGenre(){           return $this->bandGenre;        }        public function addMusician(Musician $musician){           array_push($this->musicians, $musician);           $musician->assignToBand($this);        }        public function getMusicians() {           return $this->musicians;        }      }      class Guitar implements Instrument {        private $name;        private $category;        function __construct($name) {           $this->name = $name;           $this->category = "guitar";        }        public function getName() {           return $this->name;        }        public function getCategory() {           return $this->category;        }      }      // Test Objects      $band = new RockBand("The Variables");      $bandMemberA = new Guitarist("Jack", "Float");      $bandMemberB = new LeadGuitarist("Jim", "Integer");      $bandMemberA->addInstrument(new Guitar("Gibson Les Paul"));      $bandMemberB->addInstrument(new Guitar("Fender Stratocaster"));      $bandMemberB->addInstrument(new Guitar("Hondo H-77"));      $band->addMusician($bandMemberA);      $band->addMusician($bandMemberB);      foreach($band->getMusicians() as $musician) {        echo "Musician ".$musician->getName() . "<br>";        echo "is the " . $musician->getMusicianType() . "<br>";        echo "in the " . $musician->getBand()->getGenre() . " band <br>";        echo "called " . $musician->getBand()->getName() . "<br>";        foreach($musician->getInstruments() as $instrument) {           echo "And plays the " . $instrument->getName()."";           echo $instrument->getCategory() . "<br>";        }        echo "<p>";      }    ?> 

Although this example is fairly simple, it illustrates one of the important aspects of object-oriented programming. Notice how no conditional branching occurs when the objects are tested at the end. You don't need to find out what type of Musician or Instrument you're dealing with before calling its methods. Because the rules of the interface were followed, you can trust that the objects will all respond appropriately, and uniquely to their implementation. As discussed in the previous chapter, this is what's referred to as polymorphism. Anytime you need to add another type of Musician, you can just write the new class, defining its behavior behind the standard Musician interface.

Professional PHP5 (Programmer to Programmer Series)
Professional PHP5 (Programmer to Programmer Series)
Year: 2003
Pages: 182
BUY ON AMAZON © 2008-2017.
If you may any questions please contact us: