14

I understand the idea of package scope, and at times have even thought I wanted it. However, every time I set down with a serious intent to try using it I discovered it did not fit the needs I thought it would serve.

My main issue always seems to be that the things that I wish to limit the scope of are never in the same package. They may conceptually all be linked, but the logical division of data within the application has them as separate child packages of a larger package.

For instance I may have a Mission model and I want only other Mission tools, like my missionServices, to use some methods. However, I end up with Missions.models and Missions.services as my packages, so the MissionModel and MissionService are not the same package scope. It never seems like there is a situation where packages appropriately contain the things that I would want to have elevated permissions without also included numerous things I do not wish to have those permissions; and rarely do I feel the advantage of package scoping a method justifies modifying my project architecture to place everything in the same package. Often either Aspects or some sort of inversion of control turn out to be the better approach to whatever problem I briefly considered package scoping for.

I'm curious rather this is generally considered true across all Java developers, or is just a fluke of the work I do. Is package scope utilized much in the real world? Are there many cases where it's considered good form to use, or is it seen mostly as a legacy behavior to rarely be exploited in modern development?

I am not asking anything about why package private scope is default, I'm asking when it should be used regardless of the defaults. Most discussions as to why it is default don't really get into when package scope is actually useful, instead arguing simply for why the other two commonly used scopes should not be default so package wins by process of elimination. In addition, my question is about current state of development. Specifically, have we developed to the point where other tools and paradigms make package scope less useful then it was back when the decision to make it default made sense.

dsollen
  • 1,153

5 Answers5

5

Sometime i escalate the visibility of private or protected methods to package to allow a junit-test to access some implementation detail that should no be accessed from outside.

since the junit-test has the same package as item-under-test it can access these implementation details

example

  public class MyClass {
    public MyClass() {
        this(new MyDependency());
    }

    /* package level to allow junit-tests to insert mock/fake implementations */ 
    MyClass(IDependency someDepenency) {...}
  }

It is debatable if this is a "good" usage or not but it is pragmatic

k3b
  • 7,621
2

Throughout the java.util.* package there are instances where code is written with package level protection. For example, this bit of java.util.String - a constructor in Java 6:

// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
    this.value = value;
    this.offset = offset;
    this.count = count;
}

or this getChars method:

/** Copy characters from this string into dst starting at dstBegin. 
    This method doesn't perform any range checking. */
void getChars(char dst[], int dstBegin) {
    System.arraycopy(value, offset, dst, dstBegin, count);
}

The reason for this is that the designers of the code (and java.util.* can be thought of as a rather large library) wanted the ability to have faster performance at the cost of a loss of various safety (range checks on arrays, direct access to other fields that imply the implementation rather than the interface, 'unsafe' access to parts of the class that are otherwise considered to be immutable via public methods).

By restricting these methods and fields to only be accessed by other classes in the java.util package, it makes for closer coupling between them but also avoids exposing these implementation details to the world.

If you are working on an application and don't have need to worry about other users, package level protection isn't something you need to worry about. Other than various aspects of design purity, you could make everything public and be ok with that.

However, if you are working on a library that is to be used by others (or want to avoid entangling your classes too much for later refactoring), you should use the strictest level of protection afforded to you for your needs. Often this means private. Sometimes, however, you need to expose a little bit of the implementation details to other classes in the same package to avoid repeating yourself or to make the actual implementation a bit easier at the expense of the coupling of the two classes and their implementations. Thus, the package level protection.

2

It's not all that useful, especially as a default, in a world where people tend to use the dotted names of packages as if they were sub-packages. Because Java has no such thing as a sub-package, so x.y.internals has no more access to x.y than it does to a.b. Package names are either the same or different, a partial match is no different from having nothing in common.

I guess the original developers never expected that convention to be used, and wanted to keep things simple without adding the complexity of Ada-style hierarchical packages.

Java 9 is sort of addressing this, in that you can put several packages in a module and only export some. But that will make the package scope even more redundant.

In an ideal world, they would change the default scope to 'module scope, if a containing module exists, otherwise package scope'. Then you can use it for sharing implementation within a module, allowing refactoring without breaking exported interfaces. But maybe there is some subtlety why that would break backwards compatibility, or be otherwise bad.

soru
  • 3,655
2

The type of cohesion your describing is not really the best example of where you would use package access. Package is handy for creating components, modules that are interchangable on an interface.

Here is a rough example of a scenario. Suppose your code was reorganized to be more around functional cohesion and componentization. Perhaps 3 jars like:

**MissionManager.jar** - an application which uses the Java Service Provider Interface to load some implementation of missions, possible provided by a 3rd party vendor.

**missions-api.jar** - All interfaces, for services and model
    com...missions
        MissionBuilder.java   - has a createMission method
        Mission.java - interface for a mission domain object
    com...missions.strategy
        ... interfaces that attach strategies to missions ...
    com...missions.reports
        .... interfaces todo with mission reports ....

   **MCo-missionizer-5000.jar** -  provides MCo's Missionizer 5000 brand mission implementation.
       com...missions.mco
                  Mission5000.java - implements the Mission interface.
       com...missions.strategy.mco
              ... strategy stuff etc ...

By using package level in the Mission5000.java, you can unsure that no other package, or component such as the MissionManager can tight couple to mission implemetation. That is only the "3rd party" provided component from "M co" actually creates there own special branded implementation of a Mission. The Mission Manager must call the MissionBuiler.createMission(...) and use the defined interface.

This way if the Mission implementation component is replaced we know that the implementers of MissionManager.jar didn't bypass the api and use MCo's implementation directly.

Hence we can swap out MCo-missionizer5000.jar with a competing product. (Or perhaps a Mock for unit testing the Mission Manager)

Conversely MCo can do some amount of hidding their proprietary missionizer trade secrets.

(This is related enforcing Instability and Abstractness ideas in components as well.)

Chris
  • 183
-1

Because package scope in java is not designed in the hierarchical way it is hardly useful. We do not use package scope at all and define all classes as public.

Instead we use our own access rules based on the package hierarchy and predefined package names.

If you are interested in details google for "CODERU-Rules".