Home > Articles > Programming > Java

  • Print
  • + Share This
From the author of

Packages as Units of Abstraction

Packages are a level of abstraction beyond classes, grouping sets of classes into functional units. Classes within a package may share information with each other that's protected from other packages. This allows packages to be coherent; the more they share with one another, the more likely they are to belong together.

Packages can also be coupled through public classes, and public fields and methods in those classes. It takes only a single point of interaction between two packages for them to be coupled. You may use only java.awt.Rectangle for some geometric computations, for example, but that couples your package to java.awt, which isn't found on some Java platforms. (More on that in a bit).

Java isn't the first programming language with packages. UML, among others, predates Java. But Java is in the widest use for a general-purpose programming language. (UML is a design language, not a general-purpose programming language).

There are a number of practical reasons to decrease coupling between packages and increase cohesion:

  • Compilation. When you make a change to a piece of code, you want to be able to compile all and only the pieces of code that are affected by the change. If a package has no coupling, you can safely compile only that package and be sure that you're getting everything that needs to be compiled. Similarly, if your code has high cohesion, you can be sure that if you compile the entire package, only potentially affected classes are being compiled.

  • Simpler naming. Java provides the ability to import all of the classes in a package with a single import foo.* command. Some programmers avoid doing so because it potentially imports too much, causing conflicts with custom names. User interface programming in Java can be made complicated by having to import java.util.* and java.awt.*, because both packages have a class called List. Most programmers wouldn't import java.awt since the introduction of Swing, but the javax.swing package is coupled to java.awt by classes such as Component and Color.

  • Comprehension. The smaller the number of classes in a package, the easier it is to understand. Increasing cohesion means that only related classes will be in a single package. Similarly, decreasing coupling means that if you understand all the classes in a package, you'll understand everything you need to know about it; you won't need to go looking about in other classes.

  • Reuse. When you reuse some subset of a project, it's likely that you'll need more than one class at a time. If your package is coupled to some other package, you need to reuse that package as well. The more packages you have to pick up, the more likely it is that one of them is going to make life difficult for you—for example, having a native method that hasn't been ported to the platform you're working on, or adding huge quantities of code that you aren't really using and don't really care about.

Reuse is important even if the code will never be revisited on a different project. Reuse within a single project occurs when a manager, customer, client, user, etc. asks, "This chunk of the program has feature X; why can't that other chunk of the program do X?" It's bad business, and bad form, to have to tell your manager/customer/etc., "Conceptually, what you've asked for is simple, but it turns out to be really hard because the logic is tied to some utterly unrelated piece of implementation."

These principles are obvious to any experienced programmer. You probably already have a strong intuitive grasp of when to split a package into two different packages, and when to combine them. Assigning the names cohesion and coupling gives you a hook on which to hang your decisions: You've split these classes into a separate package because they're cohesive (they all reference each other) and they're not coupled (they don't reference any other package).

  • + Share This
  • 🔖 Save To Your Account