###Software Development Lifecycle - Class Diagrams !#breadcrumbs NC State University > CSC216 > Software Engineering Overview > Software Life Cycle > Design > Class Diagrams
!#wrapper
!#row !#nav-row !#nav-prev Design !#nav-end
!#row !#class=”designIcon” role=”img” aria-label=”Design Icon” #Class Diagrams Class diagrams are a type of UML diagram, which describe the classes, states, behaviors, and relationships between classes for a software system. When analyzing requirements, we identify nouns which could represent objects or an object’s state and verbs which could represent a class’ behaviors. We then create a UML diagram to represent classes as an abstraction of a single responsibility and the relationships between classes.
!#row ##Classes In a UML class diagram, classes are represented by a box divided into three sections stacked vertically. The top section contains the class name, and in some diagrams may also include the package name. The middle section contains the class’ state or fields. The bottom section lists the class’ behavior.
The state and behaviors of a class are written so that you can directly translate them to the code for fields and methods. Both state and behaviors have a leading symbol that represents the visibility of the item. A + represents public, - represents private, # represents package, and no symbol represents default access.
- public: Any class can use the field or method through an instance of the object or the class itself (if the field or method is static).
- private: No external class can use the field or method.
- protected: An external class that is a subclass of the given class or in the same package as the given class can use the field or method through an instance of the object or the class itself (if the field or method is static).
- default: An external class that is in the same package as the given class can use the field or method through an instance of the object or the class itself (if the field or method is static).
The visibility is followed by the name of the element. For example, there is a field named eventName and two methods named isConflict. A method’s name is followed by parentheses that may include a parameter list. The parameter list could just list the types of the parameters in order. The parameters may also include names. If so, the name is listed first, followed by a colon (e.g., :), then the type.
The type of the state or behaviors is listed at the end of the line following a colon (e.g., :). The method’s type is the return type, which means the method can also be treated as that type in code!
A static field or method (e.g., the main method) is annotated with an underline. There is not a specific notation for final fields.
Abstract class names and abstract methods are represented in an italic font. Typically, abstract classes have at least one abstract method, but they do not have to. An abstract class is a class that contains common code in an inheritance hierarchy that would be inappropriate to instantiate.
An interface’s name is surrounded by the less than (e.g., <) and greater than (e.g., >) symbols. The diagram may also have a notation under the name that it is an interface. All interface methods are abstract and are shown in italics.
!#row ##Relationships There are two main relationships between classes in object-oriented programming languages like Java: generalization (i.e., is-a) and composition (i.e., has-a).
!#row ###Generalization (is-a) A generalization relationship models inheritance, when one class (the child or subclass) extends or specializes another class (the parent or superclass). The generalization relationship is modeled by using an open triangle connector where the triangle points to the parent class.
!#row ###Composition (has-a) A composition relationship is when one class has or uses an instance of another class. There are several connectors that are used to model a composition relationship depending on the nature or strength of the relationship. All connectors, except the dependency connector, represent when a class has a field (is a container) that is an instance of another class (the contained). That means the connector is annotated with information about the field like the field name. Since the connector represents the field, it is redundant to list the field in the container class. The connector may also be annotated with numbers that represent the multiplicity of the connection. If there is only a single instance of the contained in the container, the multiplicity is noted as a 1. If there are multiple objects of the contained type in the container, the multiplicity is noted as 0..*, or zero to many. That means the container stores the contained type in some type of collection like an array or object from the Java Collections Framework.
- Association Connector: An association connector is a solid line between the container and the contained. If the relationship is bi-directional, which means that each class contains an instance or collection of the other, the connector is a solid line. The connector is annotated with the field names for each class. In the example below,
Coursewould have a field calledenrolledStudentswhich would contain a collection ofStudents.Studentwould have a field calledcourseSchedulecontaining a collection ofCourses.
If the relationship is uni-directional, the arrow points to the contained class. In the example below, Schedule has a field called events which would contain a collection of Events.
- Aggregation Connector: An aggregation connector is a solid line between the container and the contained with an open diamond at the end next to the container. An aggregation connector models a whole-part relationship where the contained class represents a part of the container or whole class where the part can exist separate from the whole. For example, a car has wheels or the wheel is part of a car. But the wheel can exist separate from the car. In an above example, we showed that a schedule has events. If we consider a schedule as a whole that is made up of events, the more appropriate connector for the relationship would be aggregation.
- Composition Connector: A composition connector is a solid line between the container and the contained with a solid diamond at the end next to the container. Like an aggregation connector, a composition connector models a whole-part relationships where the contained class represents a part of the container or the whole class. Unlike the aggregation connector, a composition connector should be used when the part cannot exist separate from the whole or when the whole controls the entire life cycle of the part. For example, a line item doesn’t exist separate from an invoice. If we consider a schedule as controlling the life cycle of events and that an event cannot exist outside of a schedule, we could model the relationship using a composition connector. A composition connector may be used to model inner classes since the outer class controls the life cycle of the inner class.
- Dependency Connector: A dependency connector is a dashed line between the container and the contained. The arrow points to the contained. A dependency connector is used to show when a class uses an instance of another class as a local variable or a parameter type, but not as a field. Since there are usually many dependencies between classes in a design, the dependency connector is frequently omitted from class diagrams. An example of the dependency connector is shown in the full class diagrams, below. In the example,
Schedulerdepends onCourseRecordIOwhenloadCourses()is executed.
!#row
##Design Quality
Each Guided Project provides a UML class diagram that provides the design for the system. The Wolf Scheduler class diagram provides an example of a system that has been design with only composition relationships. The diagram makes use of an aggregation relationship between Schedule and Event since that models a whole-part relationship. The other relationships are modeled using association except for the connector between Scheduler and CourseRecordIO. The relationship between Scheduler and CourseRecordIO is modeled as a dependency since Scheduler will use CourseRecordIO in the loadCourses() method, but does not keep track of an instance of the class as a field.
However, from the diagram, we can observe redundant state and behavior with Event and Course. A future iteration of development on Wolf Scheduler may involve a refactoring of the design to incorporate inheritance, abstract classes, and interfaces. A proposed design for the next iteration of Wolf Scheduler, with methods and fields removed for brevity, is annotated with arrows that point out the generalization relationship. For example, Event is a subclass of ScheduleItem. ScheduleItem implements the Schedulable interface. Abstract classes, like ScheduleItem, and methods, like isConflict() are noted in italics. There is another notation listed, E, which represents a generic type.
!#row !#nav-end
