EJB Inheritance, Part 1
by Emmanuel Proulx09/04/2002
Java is an object-oriented language, which means it follows the principles of object-oriented programming, such as encapsulation, inheritance, and polymorphism. (Inheritance and polymorphism pretty much go together, so they are often simply referred to as inheritance, which is what I will do in these articles.) These are great principles and can be used to represent relationships between objects in very powerful ways.
Entity beans are objects that represent data coming from a persistent store, such as a database. The key word here is objects. Entity beans encapsulate the data and business logic. But what about the two other principles, inheritance and polymorphism?
The bad news is that entity beans do not easily enable the use of these principles. The good news is that if you follow certain restrictions and tricks, it can be done. This series of articles describes some techniques to put inheritance and polymorphism back into entity beans.
Why EJB Inheritance?
Most systems today use direct SQL access to flat relational databases. Since entity beans are often mapped to relational databases, why use inheritance? Let's not forget that SQL and relational database technology date back to the days of COBOL. Object-oriented programming was invented later, with some specific goals in mind:
|
Source Code Download the source code for this article. This zip file contains a WebLogic Server domain, EJB source code, and a PointBase database. Install this under C:\inherit. The admin login is:
|
- Abstraction: Modelling real-life objects.
- Reusability: Enabling subclasses to reuse the code in the base class.
- Maintainability: Objects are easier to manage than procedures.
These goals do not apply to pure data, but rather to the behavior of objects. This means EJB inheritance is likely to be visible in the code, but not in the database. We can live with that, as long as the mapping between the data and the objects is done in a smart way. The advantages of EJB inheritance should be obvious when we see an example.
Recurrent Traveler Miles -- Requirements
Imagine a company named Recurrent Traveler Miles (RTM). This company has a customer retention plan similar to the airlines' "frequent flier miles" systems. Every time you spend a specified amount of money, you obtain a point or "reward mile." When you accumulate enough points, you earn some sort of prize, typically a free flight.
In this system, there are three kinds of customers: Regular, Gold, and Platinum. The differences between these three customers are the rules used for attributing and redeeming points. Those rules are listed here:
Table 1. Customer types and requirements
Customer | Purchase amount to get one point | Number of points to get a free trip |
Regular |
$20 |
Same region: 1500 |
Gold |
$18 |
Same region: 1300 |
Platinum Note: Platinum customers get to choose a charity. RTM will give 1% of all purchases to that charity. |
$15 |
Same region: 1200 |
These numbers are all arbitrary, so don't get mad if they don't make any sense. It's just an example.
With these requirements it's easy to do a single CMP entity bean, CustomerEJB,
and put all of this business logic in a single place. Let's see what kind
of code we obtain by doing this. Here's one method:
Example 1. Single entity bean method
public int redeemPoints(int zone) {
int pts = 0;
if(getType().equals("REGULAR")) {
switch(zone) {
case 1: pts=1500; break;
case 2: pts=3500; break;
case 3: pts=10500; break;
case 4: pts=25000; break;
default: return 0;
}
} else if (getType().equals("GOLD")) {
switch(zone) {
case 1: pts=1300; break;
case 2: pts=3100; break;
case 3: pts=10000; break;
case 4: pts=22000; break;
default: return 0;
}
} else if (getType().equals("PLATINUM")) {
switch(zone) {
case 1: pts=1200; break;
case 2: pts=2850; break;
case 3: pts=9500; break;
case 4: pts=20000; break;
default: return 0;
}
}
if(getPoints() < pts) return 0;
setPoints(getPoints()-pts);
return pts;
}
How ugly. I could break apart this method into small pieces, it's true, but it wouldn't change the fact that this is bad design. The sure sign
that object-orientation is missing here is that big if() else if() else
if() block. There has to be a better way.


