Is it inconvenient for programming practice to place abstract classes inside a single package containing their derived classes?
Assuming A, B, C are derived from AbstractBaseClass and they are all part of the same java project, are form package structures ...
package com.whatever.###
AbstractBaseClass.java
package com.whatever.###.###
A.java
B.java
C.java
... generally preferred over form package structures ...
package com.whatever.###.###
AbstractBaseClass.java
A.java
B.java
C.java
?
... or few can care?
source to share
I wrote a fairly complex application that used the first example, and this is how I justified the design. In my case, there was a general interface related to the underwriting price, but a few vendors who could provide various web services that would populate the actual data. This was the package structure
com.example.pricing
\IPricingProvider.java
\AbstractPriceProvider.java
com.example.pricing.vendorA
\PricingEngine.java
com.example.pricing.vendorB
\PricingEngine.java
com.example.pricing.vendorC
\PricingEngine.java
Then in my code, I used import
to connect the motor that I wanted. Like this:
import com.example.pricing.*;
import com.example.pricing.vendorB.*;
IPricingProvider provider = Engine.create();
The advantages for me were being able to have complex and messy implementations for each vendor (two of them were quiescent based, one was web service using wsimport
, so there were a lot of Java generated files), not auto-complete Eclipse looks like a complete nightmare ... It also made it easier to transfer an individual provider to another developer.
source to share
In fact, this is generally good practice. Too many packages can get confused very quickly. Keeping the implementation classes in the same package eliminates the additional import statement and makes it easy to find the abstract class as your application codebase grows. The exception to this would be in cases where you have larger groups of implementation classes that all extend from abstract classes. So, for example, if you have a MySQL implementation and Mongo implementation from multiple abstract clans, you might want to put them in separate subpackages. Something like
com.foo.data <--- abstract classes
com.foo.data.mysql <-- impl
com.foo.data.mongo <-- impl
source to share
The package structure serves two purposes, which are sometimes different.
- Make it easy for people exploring your APIs and code to find a class that does what it wants. In this case, you want to group things together and use package names that make it obvious to anyone looking at the Javadoc where to look. This speaks to the small number of broad division packages that matter to API customers.
- Allow classes to access other package APIs. This speaks to many small groups of closely related classes.
Large scale organizations like packages don't have to depend on current implementation details, so I prefer (1) over (2).
Deep hierarchies are hard to grasp, so if adding a name element doesn't make it easier to learn your API, and doesn't help people filter out bits that are irrelevant to their current tasks, then leave that.
source to share
I think it depends on which part is more important to clients: superclass or subclasses?
The latter often happens when you think you are the first of the subclasses and just refactored some of the common parts into a superclass. Then this superclass should be in the same package and not visible publicly as Louis said in his comment. If clients need to see the types of subclasses, then you usually have this pattern.
However, when you abstract from the implementations and clients usually only work with the superclass, as in Jason's answer, then you should follow the strategy of placing each subclass in its own package. Often these subclasses need additional classes that are not relevant to the external code, so a good package for them.
source to share
Surprisingly, the answer. It depends.
If you are going to make two descendants of brothers, then one file for each (as in the three cases) makes sense. If they were small and / or you would always use both (eg directory and file), then there is a pragmatic argument for keeping them all in one.
If you create some deep inheritance hierarchy, where only the final descendant has useful functionality (the more abstract the class, the less it does), then placing it in a separate file is pointless.
source to share