A ClassDiagram is a UML (UnifiedModelingLanguage) artifact that visually shows the relationships among classes.
A ClassDiagram can be used to show different views. Here is a paraphrase of MartinFowler's UML perspectives (http://b2b.wikis.com/wc.dll?b2b~ClassDiagram~SoftwareEng) (which he adopted from SyntropyMethodology):
1. A conceptual model (each class is a concept of the domain) in which every class need not to show any attributes and the relationships among classes are very loose, like "knows", "finds", "relates", etc.
2. How the objects interact, or
3. Hard class relationships that can be directly implemented.
Using a ClassDiagram for 1 and 2 is not very adequate, IMHO, because a textual representation is easier to modify and visualize. Using it for 3 is not very adequate either because the class diagram changes too often.
A good class diagram is narrow and deep: All classes inherit from others and there is no class that has more than 10 direct subclasses (this is just a recommendation). Most classes should have no more than 3 attributes and no more than 10 methods. Attributes should be other classes or, better yet, interfaces.
Replace attributes with relationships: attributes should be implicit rather than explicit. If there are too many relationships on a class, the class should be used as the type of the attributes (replace relationship with attribute).
As a general suggestion:
1. No more than 4 relationships when the class has no inheritance relationships.
2. No more than 5 relationships (including inheritance) when the class has inheritance relationships.
No class should have more than 10 direct subclasses? Attributes should be interfaces? Are these general object-oriented design principles or specific standards for one individual company/project? They don't seem to be commonly mentioned in the well-known literature.
This contradicts most of the literature, in fact, in several respects. "No more than 10 methods", for instance, implies "you can just forget refactoring to make long methods shorter". -- DougMerritt
Very good points. Let me answer those:
1. No class should have more than 10 direct subclasses?
10 is a magic number here, it has proved to work in my limited experience. Actually I think that number should be far lower, as low as 2, but that depends on the problem at hand. It might perfectly be that you have a Character class and each individual character is a subclass, assuming each character has a different behavior. In English that would 26 direct subclasses, in ASCII that would be 256 subclasses and in UNICODE that would be more than 10,000 subclasses.
2. Attributes should be interfaces?
Every variable declaration should use interfaces, including attributes. The reason for that is that variables are not really objects, they just explicitly indicate what messages you can send (at least in Java) and what parameters are allowed. Using classes is a way to avoid polymorphism.
3. Are these general object-oriented design principles or specific standards for one individual company/project?
I guess they are proposed general standards that I'm willing to use in any project. ;-)
4. "No more than 10 methods", for instance, implies "you can just forget refactoring to make long methods shorter".
Actually, it doesn't. The purpose of refactoring is having fewer than 10 methods. You know this general rule: "Make it work, make it right, make it fast", well this 10-method-rule is in the "make it right" part of the general rule.
That is far from the only purpose of refactoring. A directly opposed rationale for refactoring is to make long methods shorter, which can have the effect of breaking up a single long method into many shorter methods. There was recently a rather long argument about this in LongFunctionsDiscussion. (I was taking the side that there shouldn't be too many methods, either, but the parties arguing that methods shouldn't be very long certainly have very good points, too.)
Given the high level of controversy seen on this subject, there's no way you can just blithely assume that everyone will agree with you that "The purpose of refactoring is having fewer than 10 methods", especially without any rationale given. -- DougMerritt
I agree that refactoring has to do more with smells rather than with "only 10 methods here". Absolutely, but as you say, it can be one of the purposes. I agree that methods should be short, AFAIK they should have only 10 sentences. Having ManyShortMethodsPerClass is one way to achieve that, and once you have achieved that, then you have another smell: You have too many short methods. Melting them into larger methods is not an option, so you can then move them to other classes to have FewShortMethodsPerClass as is explained in: http://www.talkaboutprogramming.com/group/comp.lang.smalltalk.advocacy/messages/2653.html -- GuillermoSchwarz
That URL only talks about one tiny aspect of the subject, but ok. As a pragmatic rule of thumb rather than a purist absolute, ok, yes. -- DougMerritt
Actually I think the "make it right" part should always include a DoMoreWithLess rule.
The rationale for having no more than 10 methods:
1. It is a suggestion. Certainly a language that limits arbitrarily the number of methods would be a disaster. But having in mind that if you write more than 10 methods means that your class probably needs to be divided, that's something else.
2. A class with 20 methods is doing too much.
Example 1: The Date class: Get the day, the month, the year, the day of the week, the week of the year, is it holiday? move one day forward, move one day backward, is the date valid? move one weekday forward, move one weekday backward, calculate the number of days between two dates, get the date of today, move one month forward, move one month backwards, count the number of days in a year, count the number of days in a month, count the number of weekdays in a month, count the number of holidays in a month, etc. I can go on and on. The class doesn't seem to complete ever. Actually I read that that was something that really happened in the JDK with the Date class or the Calendar class, I don't remember which.
Example 2: The class is only doing 10 gets and 10 sets. That doesn't sound like much, it is probably a Java bean, but I guess the class is assuming that every Person has only one address. Or only 2 addresses. Big mistake. One Person should have 3 attributes at most, all others should be relations to other classes. Even if there is only one address, the attribute should be Address and there should be an Address class for every country, or better yet, one big fat Address class that knows how to handle all addresses in the world, by configuration. Well that Address class should be divided in simpler classes.
I've worked many years in C++ and Java, and all the big fat classes I've seen took a lot of time to implement and a lot more time to debug and they were always buggy. It doesn't matter how much effort you add into this big fat class, there is always one more bug. Usually you start with a melt concept and never realize that it is simpler if you divide it. You can do a lot more with a lot less effort by dividing the concepts (which is a central idea in CRC and RRD methodologies).
Unless of course you have some FearOfAddingClasses.
See DeepClassHierarchies for a discussion about DeepClassHierarchies versus FatClassHierarchies. Also see FearOfAddingClasses.