I'm writing a handler for download/import of data. After inserting data to the database, several import jobs can be called, but usually it is just one. So there are two methods to get the import job(s), that can be overridden from the abstract base class, one being abstract, the other one using the first one.
Please have a look at my code and doc and tell me if you think this design is okay or what practice may be best. I'm particular irritated by my design to have the one writing the subclass having to implement getImportJob()
just to throw an UnsupportedOperationException
, it somehow came up naturally. But is the bold marked part okay or am I breaking some conventions with that?
/**
* Returns the name and parameters of the import job that may be called
* after the data has been added to the database in
* {@link #insertDataIntoDatabase(Map)}.<br>
* If the import job is called or not in the aforementioned method is
* determined by {@link #isExecutingImports()}. If there is no import job to
* execute ever, this method should return <code>null</code>. If there are
* several import jobs to be done, this method should throw a
* {@link UnsupportedOperationException} and {@link #getImportJobList()}
* should be overridden to return the names and parameters of the import
* jobs in the order they should be executed.
*
* @return the name of the single import job that can be executed or
* <code>null</code> if none can ever be executed.
* @throws UnsupportedOperationException
* If this method was called when there are several import jobs.
*
* @see #getImportJobList()
*/
protected abstract String getImportJob();
/**
* Returns a list of names and parameters of import jobs that may be called
* after the data has been added to the database in
* {@link #insertDataIntoDatabase(Map)}.<br>
* The default implementation calls {@link #getImportJob()} and returns an
* empty or a singleton list depending on <code>getImportJob()</code> having
* returned <code>null</code> or a concrete object. When this method is
* overridden to provide several import jobs to be done,
* <code>getImportJob()</code> should also be overriden, according to its
* documentation.
*
* @return a list of names and parameters of import jobs
* @throws UnsupportedOperationException
* If <code>getImportJob()</code> was overridden to throw an
* <code>UnsupportedOperationException</code> without this
* method being overridden accordingly.
*
* @see #getImportJob()
*/
public List<String> getImportJobList() {
String singleImport = getImportJob();
if (singleImport == null)
return Collections.emptyList();
return Collections.singletonList(singleImport);
}
It just occured to me that I can make both methods abstract and provide two interfaces, one for single and one for multi use, each one leaving one method abstract and implementing the other one with default according to the contract... That may be a misuse of the default concept, but I think it would serve my purpose. My question still stands.
EDIT: Thanks to the answers I changed the base class to an interface without the single-Job method and added an inheriting interface with the single-Job method and a default for the Job-List method.
getImportJobList()
that either returns null or a list with a single element doesn't make much sense to me.getImportJob()
. But if there are several import jobs, he is expected to overridegetImportJobList()
as well.UOE
is the pinnacle of code smells, and should only be used as a last resort. If a type does not support a behavior, it should not be forced to implement said behavior (or you violate ISP). If your type implements the interface and throws anUOE
, it's violating LSP. If you're forced to throwUOE
, the contract of the interface you are implementing is too broad for the type that is implementing it.