This lesson deals with building cohesive, conceptually sound class structures for readability and maintainability. Start off by creating an ASP.NET project with a Default.aspx file.
In the previous lesson, we learned how to create multiple classes that exist side-by-side within the same file, and under a common namespace outer container. While this can be useful for quickly testing out code and keeping it easy to reach, larger applications will make this impractical. In these cases, it is often preferable to separate classes into their own files. You can add a class to the project by right-clicking on it from within the Solution Explorer, and selecting from the context menu:
From the resulting context menu select:
Add > New Item…
And in the dialogue, choose the “Class” item under the “Visual C#” tab:
To help keep track of what classes are in your Class files, you would typically want to name the file the same as the class itself. In this case, we are going to create an Automobile class:
Open up this Class file and write out the following code for it, omitting the method implementation details for now:
It can be difficult for beginners to quickly glimpse the constituents of a large class and separate the properties from the methods, especially if a method has a return type. When scanning through the class, try to look for the parentheses, such as in DetermineMarketValue(), as a “dead giveaway” that the member is a method. Also, although not strictly enforced, the rule of thumb is that properties are at the top of the class, and below that are the methods.
And now, in the Default class, create an instance of the Automobile class and set its properties, along with calling some of its (empty) methods:
Notice that even though each of these classes are in their own separate files, they are able to “see” each other and that is because they share the same namespace. Also, note that even though the Automobile class is not marked as “public” it is still available to other classes within the namespace. This is because in absence of an accessibility modifier, it defaults to accessibility level called “internal” (meaning internally accessible to this namespace only):
Going back to the Automobile class, notice how large it is (even without any real implementation details). When you consider how this class is structured (presumably in anticipation of fulfilling a need within a broader application) it may, seem like the class is highly cohesive and sticks to the single responsibility principle. However, just because all of these methods and properties have something to do with a car, doesn’t mean they should all belong in the Automobile class. For example, this set of properties refer to a buyer’s details so perhaps it’s best to have these within a separate class:
Go through the remaining list of properties and methods and try to anticipate which items are best moved into other classes.
There is a rule of thumb that some software developers subscribe to that says every class should be no longer than the length of the screen its being viewed on (setting aside that screen and font sizes aren’t uniform). In other words, you shouldn’t have to scroll down to see the rest of the code in the class. While simplistic, the wisdom here again is to keep the principle of Single Responsibility in mind and break up a single large class into a bunch of smaller classes whenever possible.
Let’s apply what we’ve learned about code refactoring from previous lessons to break up this single, monolithic, Automobile class into a series of smaller classes - each within their own file within the Solution Explorer:
The purpose of having highly "cohesive" classes is to reinforce the single responsibility principle we've discussed before. Cohesive classes have properties and methods that are directly related to each other. Other extraneous details or functions can be moved to other, more cohesive classes. This allows you, the programmer, to create an application that can withstand time and change in the architecture of the program. We'll discuss architecture later, but think of the way that short, specific methods allow you to affect the functionality of the program without modifying its core components on a larger scale.
Here is how each individual class now breaks down (again, the implementation details are not important, just focus on the way the classes are restructured):
While having many small, cohesive classes is preferred to just a few large classes, organization can become an issue. A useful organizational technique is to group class files into folders relative to their problem domain. This is especially useful when a project grows larger and you need to locate a class in order to update it, and so on. Simply right click on the Solution Explorer and select:
Add > New Folder
And after you name the folder you can select all of the class files you want to have added to this folder and drag/drop right into it. Here we labeled this folder as “Domain” to signify the domain layer of concern. However, as you move forward you can separate into other folders that represent other conceptual layers of your codebase:
While on the topic of navigating within your project there are some tools Visual Studio provides to aid this task. There are list boxes at the top of the main window that let you move between various (1) projects, (2) classes, as well as their (3) fields and properties:
Another handy tool is the ability to navigate to a class definition by right-clicking wherever that class is referenced and selecting either “Peek Definition” (displays class inline) or “Go To Definition” (jumps to class):
You can also navigate to different classes by clicking on the downward arrow in the upper-right corner of the main window:
The flip-side of finding a class definition would be to find all instances of the class within your project. You can right-click on the class name once again and this time select “Find All References”:
A window will pop-up describing where the class is being referenced (jump to the line of code with the reference by clicking on the line shown):
Sometimes you want to compare information between, and within, different classes. To satisfy this you can have multiple windows open by clicking/dragging tabs anywhere on the screen and hovering over the multiple docking options available (here it docks to a horizontal window below the existing main window):
You can use this docking system with just about any window within Visual Studio in order to customize it to your needs.
Also, be aware that this icon in the upper right-hand corner of the main window lets you split a window into two windows so that you can view different parts of the same class, each within its own window, for instance:
You can also right-click on any tab and select whether or not you want to move it another vertical/horizontal tab group:
Lesson 37 - Creating Class Files Creating Cohesive Classes and Code Navigation