This is how to implement abstraction for the purpose of folding common code into an abstract class that nevertheless needs to work with different data depending on the extending classes.
Our example is DAO code using MongoDB.
Here we'll implement methods create() and readByOid(). They will need to use different MongoDB collections (and Morphia datastores). Also, there are other peculiarities needed like the .class of the caller.
01.
import
com.etretatlogiciels.mongo.MongoCollection;
02.
03.
public
abstract
class
BaseDao< T >
04.
{
05.
protected
abstract
MongoCollection getMongoCollection();
06.
protected
abstract
Class< T > getClazz();
07.
08.
public
T create( T entity )
09.
{
10.
getMongoCollection().getMorphiastore().save( entity );
11.
return
entity;
12.
}
13.
14.
public
T readByOid( ObjectId entityoid )
15.
{
16.
Query< T > query = getMongoCollection().getMorphiastore().createQuery( getClazz() );
17.
18.
query.field(
"_id"
).equal( entityoid );
19.
return
query.get();
20.
}
21.
}
In the two classes below, AccountDao and AddressDao, what's peculiar to the class is implemented (forcibly) for BaseDao to call. Any methods that are different and cannot be in common between AccountDao and AddressDao are implemented in their respective classes (and not in BaseDao).
01.
import
com.etretatlogiciels.mongo.MongoCollection;
02.
03.
public
class
AccountDao
extends
BaseDao< Account >
04.
{
05.
private
static
MongoCollection mongo =
new
MongoCollection(
"accountdb"
,
"accounts"
);
06.
07.
public
AccountDao() { }
08.
09.
private
MongoCollection getMongoCollection() {
return
mongo; }
10.
private
Class< Account > getClazz() {
return
Account.
class
; }
11.
12.
/* AccountDao-only implementation */
13.
...
14.
}
01.
import
com.etretatlogiciels.mongo.MongoCollection;
02.
03.
public
class
AddressDao
extends
BaseDao< Address >
04.
{
05.
private
static
MongoCollection mongo =
new
MongoCollection(
"addressdb"
,
"addresses"
);
06.
07.
public
AddressDao() { }
08.
09.
private
MongoCollection getMongoCollection() {
return
mongo; }
10.
private
Class< Address > getClazz() {
return
Address.
class
; }
11.
12.
/* AddressDao-only implementation */
13.
...
14.
}
We won't flesh this out, just enough to show the distinction between two or more sets of data. And we won't show super class MongoDB.
01.
package
com.etretatlogiciels.mongo;
02.
03.
import
com.google.code.morphia.Datastore;
04.
import
com.google.code.morphia.Morphia;
05.
import
com.mongodb.DBCollection;
06.
07.
public
class
MongoCollection
extends
MongoDB
08.
{
09.
private
String collectionname;
10.
private
DBCollection collection;
11.
12.
public
MongoCollection( String databasename, String collectionname )
13.
{
14.
super
( databasename );
15.
this
.collectionname = collectionname;
16.
this
.collection =
this
.database.getCollection( collectionname );
17.
}
18.
19.
public
String getCollectionname() {
return
this
.collectionname; }
20.
21.
public
DBCollection getCollection()
22.
{
23.
return
this
.collection;
24.
}
25.
26.
private
Morphia morphia =
null
;
27.
private
Datastore morphiastore =
null
;
28.
29.
/**
30.
* If Morphia use is desired, get its Datastore for this database.
31.
* @return Morphia datastore.
32.
*/
33.
public
Datastore getMorphiastore()
34.
{
35.
if
(
this
.morphiastore ==
null
)
36.
{
37.
this
.morphia =
new
Morphia();
38.
this
.morphiastore = morphia.createDatastore( getMongodb(), getDatabasename() );
39.
}
40.
41.
return
this
.morphiastore;
42.
}
43.
}