Comprehensive Guide to Software Design and UML Class Diagrams

The Software Design Phase and Core Questions

The software design phase is defined as the process of specifying the structure of how a software system will be written and how it will function, without actually writing the complete implementation. This stage serves as a critical transition from the "what" of a system—defined by its requirements—to the "how" of the system. During this phase, architects and developers must answer several fundamental questions. These include determining which specific classes are necessary to implement a system that meets all established requirements, what fields and methods each of those classes will contain, and precisely how these classes will interact with one another.

Methodologies for Designing and Identifying Classes

Identifying classes often begins with an analysis of the project specification and requirements. A common heuristic employed is that nouns within the documentation represent potential classes, objects, or fields, while verbs indicate potential methods or the responsibilities assigned to a class. One effective exercise for this is the use of CRC cards, where CRC stands for Class, Responsibility, and Collaborators. Developers write the names of classes on physical or digital index cards. Next to each class name, they list its responsibilities, which are the problems to be solved or tasks to be performed, typically described as short verb phrases. They also list collaborators, which are other classes to which this class sends messages. It is important to note that collaboration is often asymmetric. Beyond CRC cards, UML diagrams—including class diagrams and sequence diagrams—are the primary tools for visualizing these designs.

Introduction to the Unified Modeling Language (UML)

The Unified Modeling Language (UML) is essentially a collection of pictures used to describe an object-oriented (OO) system. Programming languages themselves often lack the abstraction required for effective OO design, making a visual standard necessary. UML is an open standard widely adopted across various industries. It can be interpreted in two primary ways: as a descriptive language or as a prescriptive language. As a descriptive language, it utilizes a rigid formal syntax akin to a programming language. As a prescriptive language, its use is shaped more by convention and usage. In practice, it is considered acceptable to omit specific elements from UML diagrams if they are not required by the development team, supervisors, or instructors for the task at hand.

Practical Applications of UML in Software Development

There are three primary ways UML is used in professional environments. First, it is used as a sketch to communicate specific aspects of a system. This can take the form of forward design, where UML is created before coding, or backward design, where it is used as documentation after the code is written. These sketches are often done informally on whiteboards or paper to convey selective, rough ideas. Second, UML serves as a blueprint, which entails a complete and detailed design intended for implementation. This often involves Computer-Aided Software Engineering (CASE) tools. Third, UML can function as a programming language itself. With certain specialized tools, code can be auto-generated directly from the UML and executed. This approach is only considered beneficial if the auto-generation process is faster than writing code in a traditional programming language.

Components and Internal Structure of UML Class Diagrams

A UML class diagram is a visual representation of the classes within an OO system, detailing their fields, methods, and the connections between them, such as interactions or inheritance. However, these diagrams do not represent everything; they typically exclude the specific algorithmic details of how behaviors are implemented and the fine-grained details of class interactions. A single class in a diagram is represented as a box divided into sections. The top section contains the class name. If the class is an interface, the label <<interface>> is written above the name. If the class is abstract, the name must be written in italics. The middle section contains attributes or fields, and the bottom section contains operations or methods. While trivial methods like getters and setters may be omitted to reduce clutter, no methods should be omitted from an interface. Furthermore, inherited methods are generally not included in the subclass box.

Defined Syntax for Characterizing Class Attributes

Attributes, also known as fields or instance variables, follow a specific syntax: visibility name:type[count]=default valuevisibility \text{ } name : type [count] = default \text{ } value. Visibility is indicated by specific symbols: + for public, # for protected, - for private, ~ for package (the default), and / for derived attributes. A derived attribute is one that is not explicitly stored but can be computed from other existing attribute values. If an attribute is static, its name must be underlined. For example, a private balance field with a default value would be written as balance:double=0.00- balance : double = 0.00. The [count][count] parameter is optional and used for arrays or collections.

Syntactical Standards for Class Operations and Methods

Class operations or methods follow a notation similar to attributes: visibility name(parameters):return typevisibility \text{ } name (parameters) : return \text{ } type. The same visibility symbols apply: + (public), # (protected), - (private), and ~ (package). Static methods must be underlined. Parameters are listed within the parentheses using the format (name:type)(name: type). If a method is a constructor or has a return type of void\text{void}, the return typereturn \text{ } type portion of the notation is omitted. An example of a public static method for calculating distance between two point objects would be represented as: +distance(p1:Point,p2:Point):double+ distance(p1: Point, p2: Point): double. Comments can also be added to diagrams, represented as a folded note icon attached to the relevant class or method via a dashed line. This is seen in examples like the Cloneable\text{Cloneable} interface, which is a "tagging" interface with no methods.

Modeling Relationships: Generalization and Inheritance

Relationships between classes are broadly categorized into generalization and association. Generalization represents an inheritance relationship, covering both inheritance between classes and the implementation of interfaces. These hierarchies are drawn top-down, with arrows pointing upward toward the parent. The style of the line and the arrow changes based on the nature of the parent: a solid line with a black arrow is used for a standard class; a solid line with a white arrow is used for an abstract class; and a dashed line with a white arrow is used for an interface. It is standard practice to omit trivial or obvious generalizations, such as the relationship where every class inherits from the Object\text{Object} class.

Multiplicity and Navigability in Associational Relationships

Association refers to a usage relationship between classes. There are three main components of an association: multiplicity, name, and navigability. Multiplicity indicates how many instances of a class are involved in the relationship. Common notations include * for zero, one, or more instances; 11 for exactly one; 2..42..4 for a range between 22 and 44 inclusive; and 3..3..* for three or more. The name of the relationship clarifies the nature of the link between objects, and navigability indicates the direction of the interaction. For example, a one-to-one relationship exists where each student must carry exactly 11 ID card, while a one-to-many relationship exists where one rectangle list can contain many (*) rectangles.

Distinguishing Aggregation, Composition, and Dependency

There are specific types of associational relationships with varying degrees of strength. Aggregation represents a "is part of" relationship and is symbolized by a clear white diamond. An example is the relationship between a Car\text{Car} and an Engine\text{Engine}. Composition is a stronger version of aggregation, where the component is "entirely made of" the whole; in this case, the parts live and die with the whole. This is symbolized by a black diamond, such as the relationship between a Book\text{Book} and its Pages\text{Pages}. Dependency represents a "uses temporarily" relationship, symbolized by a dotted line. This is often an implementation detail rather than an intrinsic part of the object's state, such as a Lottery Ticket\text{Lottery Ticket} class using a Random\text{Random} number generator.

Practical UML Tooling and Implementation Examples

Various tools exist for creating UML diagrams, ranging from free to commercial suites. Violet is a popular free tool, while Rational Rose and the Visual Paradigm UML Suite (which offers a community edition) are prominent professional options. Examples of complex systems captured in class diagrams include a Voting Program featuring Voter Authentication\text{Voter Authentication}, Ballot Creation\text{Ballot Creation}, and securePW\text{securePW} classes. Another example is a Movie Rental system involving Rental Item\text{Rental Item}, DVD Movie\text{DVD Movie}, VHS Movie\text{VHS Movie}, Video Game\text{Video Game}, Rental Invoice\text{Rental Invoice}, Customer\text{Customer}, and Checkout Screen\text{Checkout Screen}. A final example is a StudentBody\text{StudentBody} system where a Student\text{Student} class (containing fields for names and addresses) is associated with an Address\text{Address} class with a multiplicity of 11 unit to 100100 students.

Comprehensive System Exercise: Texas Hold 'em Poker Design

To practice class design, consider a Texas Hold 'em poker game. The system must support between 22 and 88 human or computer players. Each player has a name\text{name} and a stack of chips\text{stack of chips}. Computer players specifically require a difficulty setting of easy, medium, or hard. The logic of the hand involves a dealer collecting an ante, shuffling the deck\text{deck}, and dealing each player a hand\text{hand} of 22 cards. Betting rounds are interleaved with the dealing of shared cards from the deck. Players must eventually choose to fold, check, or raise. At the end of the round, the system must compare hands to determine the winner of the pot\text{pot}. Designing this system requires identifying the necessary classes (Player, ComputerPlayer, Dealer, Deck, Card, Hand, Pot), defining their responsibilities and collaborations, and drawing a full class diagram reflecting generalization (e.g., Human vs. Computer players) and association (e.g., Player to Hand).