Section 12.6. Essential and Nonessential


12.6. Essential and Nonessential

So far, we have walked you through a very simple example, and we have made sound choices at every step. In more complex cases, even the best of us will make mistakes. We will head down blind alleys. We will group things together that might belong in separate abstract categories, but should, perhaps, share an interface. These are not so much errors as judgment calls, and skill at recognizing them and making the correct decisions comes only with experience.

For now, the most important questions to ask include:

  • Do I need this class?

    We are often tempted to create too many inherited classes. When we seek more generic, higher level abstractions, it is often possible to use only the more abstract class. Of course, it is possible to carry that tendency too far. If your methods contain a lot of "if's" to handle various subtypes, that might be a case where you should inherit and overload the method.

  • Should I get functionality by inheritance or composition?

    Inheritance should be reserved only for cases where a class is a more specific variety of the base class. For example, you might have a Person class, and then you might have Employee and Customer classes inherit common attributes and methods from Person. This is frequently called an "is-a" relationship, as in "A User is a Person." If your proposed inheritance relationship makes sense phrased that way, it might well be a good candidate for inheritance.

    Composition is when you use a class as an attribute. To extend our example, you might have an Address class. You might be tempted to have Person inherit from Address. But a Person is not an Address. Try it: "A Person is an Address." Nope. Instead, you should just have an instance of the Address class as an attribute of Person. Such a relationship is often called a "has-a" relationship, as in "A Person has an Address." If the relationship makes sense phrased that way, it is a good candidate for composition. Another way to recognize that you've wrongly used inheritance is if you end up having a radically different class inherit from the same base class. For example, suppose you have a class, Building. Would it make sense for Building and Person to inherit from Address? Are Buildings and Persons more specific instances of the same general type of thing? No, they are not. Building and Person should get Address functionality by composition.

  • Does this attribute or method belong here?

    If you find yourself specifying nearly identical methods in more than one class, this should make you ask if the classes should have a common base class from which they should inherit, or if there should be a new unrelated class that they all share by composition.

    If the functionality is the same for a set of classes, and the classes are specific instances of a more general type, the method should be on the general class. For example, a changeName() method should probably be on Person, not on Employee or Customer, because the functionality is the same for all three classes. By contrast, a changeEmployeeNumber() method should be only on Employee. It should not be on Person, because not all Persons are Employees. There may also be methods that are common to both Employee and Customer types, but are radically different in implementation. For example, a changePassword() method might change a password in a system-wide LDAP server for an Employee, but might just change a record in a Web site database for a Customer. This is easily done by writing separate methods in each class.

    But should you add a changePassword() method on Person? If you want to be able to call the method when treating either a Customer or an Employee as a Person, then you should. But you don't have to implement the method on Person. You can declare Person.changePassword as abstract, and then, if you call the method on a Person, it will call the correct method based on what type of Person (Employee or Customer) the Person is. Note that if a class contains any abstract methods, the class itself must be declared abstract and it cannot then be instantiated. Also note that this is often best accomplished not through abstract classes, but through interfaces (see Eckel, pp. 321322).

These are by no means the only considerations that come to bear on what classes to create and how to arrange and implement them, but they do represent a good start. They are a foundation on which you can build best practices out of your own experience and environment.

Whole books have been written on the topics of object-oriented analysis and object-oriented design. CRC cards are only one part of an array of techniques that can be applied to OOA/OOD. The Unified Modeling Language (UML) is popular in many MIS circles. UML consists of a variety of different diagrams which are used to model parts of an object-oriented design. They are:

Am I Mature? Or Are You My Mommy?

Let us point you at one more business buzzword link. Even though we think this particular site and their work are being ill-applied by many well-intentioned IT managers, there is still a great deal of value in the Carnegie Mellon Capability Maturity Model (http://www.sei.cmu.edu/cmm/). At the very least it provides an objective way to assess the level of process sophistication you have in your organization.

The CMM defines five levels of maturity:

  1. Initial

  2. Repeatable

  3. Defined

  4. Managed

  5. Optimizing

If we may grossly oversimplify (and why should we stop now?), "Initial" means you do things differently every time. You just make your best guess about what the right thing to do is, and you do it. "Repeatable" means that you have hit upon a method that appears to work, and you use it consistently. "Defined" means that somebody has written it down. "Managed" means that the process is actively maintained and supervised in an effort to adapt it to changing circumstances. "Optimizing" means that measurements ("metrics") are made that objectively assess the process, and ensure that continuous improvement takes place and can be so proven.[*]

What we have shown you in this chapter probably falls in the Repeatable category, a long way from the engineering and management nirvana of Optimizing.


[*] The problem that seems to come up with this system is that very bad processes may be very mature and very good processes may be relatively immature. Obviously, however, an Optimizing process must be steadily moving towards the good.

  • Class Diagram

  • Sequence Diagram

  • Collaboration Diagram

  • Use Case Diagram

  • Activity Diagram

  • Component Diagram

  • Deployment Diagram

Using the simple but effective technique of CRC cards can be a good place to start, but you may soon want to move up the OOA/OOD ladder to use tools like Umbrello[6] to make UML diagrams, and perhaps to use the whole UML toolset.[7] Many organizations that we know of will pick and choose various techniques and tools. No matter how far down the road of formal software engineering you go, you must at least make some effort to have a repeatable process that incorporates continuous improvement.

[6] http://uml.sourceforge.net/index.php

[7] http://www.uml.org/



    Java Application Development with Linux
    Java Application Development on Linux
    ISBN: 013143697X
    EAN: 2147483647
    Year: 2004
    Pages: 292

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net