Fog Creek Software
Discussion Board




Loading class hierarchy

In our current project we are working with a big class hierarchy, our problem is that when showing data we often load a big part of the hierarchy only to show a small part. Does anyone have a good solutions or pattern for loading only part of a class hierarchy? It is of course not always the same thing we want to show.

Rasmus B.
Tuesday, June 17, 2003

Technology?

Philo

Philo
Tuesday, June 17, 2003

Java, but it should not matter, the problem would be the same in C++ or C# I presume.

Rasmus B.
Tuesday, June 17, 2003

System.loadClass( "className" ) and it won't be loaded untill this explicit call.

http://www.javaworld.com/javaqa/2003-03/01-qa-0314-forname_p.html

Evgeny Goldin
Tuesday, June 17, 2003

Talking about ClassLoaders: http://www.javaworld.com/javaqa/2003-06/01-qa-0606-load_p.html

Evgeny Goldin
Tuesday, June 17, 2003

Sorry, didn’t seem to make my self clear enough. I have no problem loading classes. My problem is to decide witch classes to load. Example:
A User object contains a Pet and a Car object. I want to show a list of users with the pets they have, like this:

Joh – Dog
Marry – Lam
Peter – Ants.

On my user object I would normal have a User.getUser(id) or something like that, but that would load the User with the Pen and Car and I don’t need to show the car.
I could in my business/control object do something like: User.getList(). Then go through all of the list and call User.getPet() (or what ever).
The problem is that this is a pretty extensive system, so classes is called from all over, and to add to the complexity the business/control object do not always know what is to be shown on the frontend.

Just a tiny bit of system ;)

Rasmus B.
Tuesday, June 17, 2003

Apparently you have several concepts and relations between them. You have persons, pens, cars, and ownership, correct?
And you have modelled the ownership by actually including the owned objects with the owner objects?

You might like to try a different approach, where you have manager objects, one for each concept.
So you would have a people-manager object, a pen-manager object, et cetera.
You make the manager object responsible for loading the actual data.
Now you have several choices to model the relationship. If it is fairly static, you might choose to add an identifier to the person objects and have the identifier point to the proper pen object (like a foreign and primary key in a relational database design).

If you decide you need to show the pen owned by John, ask the people-manager object to give you John, and then use the identifier owned by John to go to the pen-manager object to ask for the pen.

If you want to be more flexible, you might create an additional manager object, one that manages who owns which pen or pens. Same for the car or whatever.

Hope this helps.

Practical Geezer
Tuesday, June 17, 2003

Thanks...but I need the system to be more dynamic. With manage object I would either end up with a lot of manager object (ManagerUserLoadCar, ManagerUserLoadCarAndPet, ManagerUserLoad) or a lot of functions on the manager object (one for each possible combination of classes loaded e.g. ManagerUserLoad.loadCar(), ManagerUserLoad.loadPet(), ManagerUserLoad.loadCarAndPet()).
If possible it would be nice to say something like user.get(id, [what to load, with out ending up with a very long parameter list])

Rasmus B.
Tuesday, June 17, 2003

Think you have a database with the different entities, and their stored properties like this for example:

TABLE CAR
  ID_CAR        NUMBER
  YEARMODEL  VARCHAR2(10),
  MAKE            VARCHAR2(50),
  MODELNAME VARCHAR2(50),
  NUMDOORS  NUMBER

TABLE PEN
  ID_PEN        NUMBER,
  COLOR          VARCHAR2(10),
  INKCOLOR    VARCHAR2(10),
  IS_PENCIL    VARCHAR2(1)

TABLE PET
  ID_PET          NUMBER,
  TYPE              NUMBER, -- 0=dog 1=cat
  COLOR          VARCHAR2(10),
  NAME            VARCHAR2(30) DEFAULT 'SNOOPY';


For each of these enities create objects like this:

TCar = class(TObject)
  {data struct for storage goes here}
public
  constructor Create(ID :Integer);
  procedure Load(ID:Integer);
end;

TPen = class(TObject)
  {data struct for storage goes here}
public
  constructor Create(ID :Integer);
  procedure Load(ID:Integer);
end;

TPen = class(TObject)
  {data struct for storage goes here}
public
  constructor Create(ID :Integer);
  procedure Load(ID:Integer);
end;

The create-method of these objects would take the ID used to store the data in the tables, and populate themselves upon creation.
Then you can have an owner object, something along
the lines of:

TOwner = class(TObject)
Childs : TList  // List of pointers to owned objects.
public
  constructor Create(ID :Integer);
end;

Code to load stuff follows:

var
  TheOwner : TOwner;
begin
  TheOwner:=TOwner.Create;
  TheOwner.Childs.Add(TPen.Create(1));
  TheOwner.Childs.Add(TCar.Create(4));
  TheOwner.Childs.Add(TPen.Create(9));
end;

This ofcourse is enormously simplified, but it should give you a flexible system. Just create more and more entity containers as the need to store more entities arise.

Most languages have some way of run time type information, so when your "owner"-object traverses its list of child objects you should be able to figure out what type of object you are dealing with, be it pens, pets or something completely different.

Patrik
Tuesday, June 17, 2003

I'm having trouble understanding exactly what you want, but I think it's lazy loading.

In lazy loading, you don't perform the load action until the first time the method is called. So, for instance, your object would have fields like:

Pet[] pets;
Car[] cars;

and then your getters would look like:

public Pet[] getPets()
{
  if (pets == null)
      loadPets();

  return pets;
}

(note that code is not thread safe in its current form).

This method will be efficient if you are not calling the child getters frequently. If you are almost always loading them, it's probably not a very efficient way to do it.

Matt Christensen
Tuesday, June 17, 2003

Yes.  What Matt said.  Lazy Load: http://www.martinfowler.com/eaaCatalog/lazyLoad.html

Stress
Tuesday, June 17, 2003

How are the objects being displayed?

B#
Tuesday, June 17, 2003

What mechanism is being used to persist the data?  Are you using JDBC calls?  An O/R tool like Toplink?  JDO?

I'll second the post about lazy loading as an answer to this sort of problem.

-Thomas

Thomas
Tuesday, June 17, 2003

http://www.vico.org/pages/PatronsDisseny/Pattern%20Proxy/ could maybe be of use?

Just me (Sir to you)
Tuesday, June 17, 2003

This is gonner get complicated...;-)

Yes, I want something like lazy loading, but due to the way oure system it build (using soap, xml and xslt) we want to know what to load when the object is created, so User.getUser(); User.loadPet(); User.loadCar(), is a no go.
I could do a User.getUser(userId, WhatToLoad){
if(WhatToLoad.load("Pet")){
this.loadPet();
}
}

The problem is that we have a complicated class structur, and if there was any way to make the loading of additional classes, more or less dynamic/automatc it would make it much easy'er for us.

Rasmus B.
Tuesday, June 17, 2003

Just a thought here- are you sure you are not talking about loading Objects rather than classes?  I only ask because I have never had a situation in which too many of my classes being loaded caused a performance problem.  Too many of Java's classes loading maybe, but not my own.

If you are having this problem with classes, how does it manifest?

If the problem is that you have complex objects and only want to load the specific data you need for any given task, I have had this problem in the past and gone a long way towards solving it.  Let me know.

Erik Lickerman
Tuesday, June 17, 2003

In our shop, we have a custom n-tier architecture (.NET, C#) that handles "loading" the data into our data, business, and presentation layer objects. While I don't understand a lick of Java, the concepts should be the same.

Our objects are based on the "lazy loading" principle discussed in early posts (however we call it "late loading").

Basically, when a Person is instantiated, we only load the attributes of the Person itself (Name, Weight, DateOfBirth, whatever) etc. For related entities, a "shell" collection is created, but not loaded. For example, If I say Manager.GoGetMePerson(ID = 101), I'll receive back a Person object (John Doe, 212, 1969.04.21) and that person will have both a Person.Pets collection, and a Person.Cars collection. These collections are initially empty. Why drag back the data if we don't need it. On first access of one of these collection, it populates itself.

This is quite handy in that it significantly reduces the time involved to go get a Person object. The drawbacks are: (1) there's 2 round trips to the DB -- one to get the Person object, and one to get the .Pets collection -- however this is mitigated by the fact that we're not going and getting the unneeded .Cars collection. The other (2) drawback is that there's a lot of extra coding to detect if the collection is already populated or not. Essentially, on every member you've got to insert an IF statement:

If I'm not already populated, Then go get my data.

It seems to work well for us, but if you haven't built it in from the ground up, and you've got a large number of objects, then you're looking at a large coding/testing effort to add it in after the fact.

Sgt. Sausage
Tuesday, June 17, 2003

"Thanks...but I need the system to be more dynamic. With manage object I would either end up with a lot of manager object (ManagerUserLoadCar, ManagerUserLoadCarAndPet, ManagerUserLoad) or a lot of functions on the manager object (one for each possible combination of classes loaded e.g. ManagerUserLoad.loadCar(), ManagerUserLoad.loadPet(), ManagerUserLoad.loadCarAndPet())."

I think you misunderstood.
There would not be a manager object for each combination of objects.
The point is that you have objects that manage other objects.
So there will be only a car manager, a pet manager, a user manager, for every single class of objects that you have.
Now, if you need to show a user with a car and a pet, you ask the user manager to provide the user, the pet manager to provide the pet, and the car manager to provide the car.
The manager object can determine if it is already in memory, or if it needs to be loaded.
As long as you don't need an object, it you don't ask the manager and it does not get loaded.
This gives you all the flexibility you need, plus it makes maintenance a lot easier, because each object and class has clear responsibilities.
Need to add grannies? Add a granny class with granny specific attributes, and a granny manager.
Need to change storage strategies? Only need to change the affected manager objects, without further changes to the code, because your code can continue to rely on the manager object to provide the requested data, without knowledge of where it came from.

I'd add a diagram if I could to make things a bit clearer...
May this meta-code helps a bit:

class UserClass {
  ... Add all your innate user attributes
}

class UserManager {
  member GetUserData (UserId) as UserClass
}

class PetClass {
  ... Add all your innate pet attributes
}

class PetManager {
  member GetPetData (PetId) as PetClass
}

class CarClass {
  ... Add all your innate car attributes
}

class CarManager {
  member GetCarData (CarId) as CarClass
}

And some code:
...
  UserManager GetUserData(thisUserId)
  CarManager.GetCarData(thisCarId)
  ...  Display the data ...

  UserManager GetUserData(otherUserId)
  CarManager.GetCarData(otherCarId)
  PetManager.GetPetData(thisPetId)
  ...  Display the data ...

Obviously, the managers decide where to get the data. And this may change without consequences. Plus, you only get, and thus load, the data you actually need, when you need it.
The managers might employ any strategy for load and unloading data and you can change it whenever you see fit.

As I said before, you can store the ids of cars, pets, or whatever, as an attribute of the user class, or you can find a more flexible mechanism. But realise that when you add it as an attribute of the user class, you create dependencies that might come back to haunt you later.

Hope this helps. And sorry if I misunderstand your problem.

Practical Geezer
Wednesday, June 18, 2003

This is great, thanks for the help, great solutions you have; I will remember them when the next project comes around.

But I can see that I haven been precise enough in my description of the problem (or rather, now I know more about the problem then before).

The problem is that a user request a list of Users through a soap interface, the list is loaded, converted to xml an then send back. Often the user making the request only need some part of the User xml (Like the name and the Pet) so a lot of the XML is unnecessary.

Now what I would like to do is to making it possible for the user making the soap request to tell what to load; something like: get UserList and their Pets, but not their Car.

So the user only gets one shot a loading a user list. It is not possible to load the rest of the information when needed, it must be loaded the first time.

Rasmus B.
Wednesday, June 18, 2003

Share the "views" on you sets by means of a flyweight ( http://www.vico.org/pages/PatronsDisseny/Pattern%20Flyweight/ ).  Basically the client requesting the data is going to have to specify what he will need later on. This is exactly the same as you would do e.g. with a database and a SQL query. You can "objectify" the query as in http://www.vico.org/pages/PatronsDisseny/Pattern%20Command/ if you fancy.

Just me (Sir to you)
Wednesday, June 18, 2003

"The problem is that a user request a list of Users through a soap interface, the list is loaded, converted to xml an then send back. Often the user making the request only need some part of the User xml (Like the name and the Pet) so a lot of the XML is unnecessary.

So the user only gets one shot a loading a user list. It is not possible to load the rest of the information when needed, it must be loaded the first time."

Ah, I see, and you are right, this constraint is rather important. Makes you appreaciate good requirements development, right ? :-)

Anyway, my knowledge is not specific enough to help you further, so good luck with all the other help you already received and probably still will.

Practical Geezer
Wednesday, June 18, 2003

One thing I would certainly do is run some benchmarks to see if leaving out certain portions of the XML is particularly beneficial, performance wise.

If it doesn't end up making much of a difference, then you'll be adding a lot of complexity for not much advantage.

Matt Christensen
Wednesday, June 18, 2003

Thanks for all the help and suggestions, and yes good requirement specifications are always important and we knew that it could be a problem when we started. But the size of the xml is not current a problem, but we are still in development so we will have to see when we go into testing.

Once agine thanks :)

Rasmus B.
Thursday, June 19, 2003

Rasmus,

My first instinct is fine and course grained objects:

http://c2.com/cgi/wiki?CoarseGrainedEntityBean
http://java.sun.com/blueprints/patterns/CompositeEntity.html

This not unlike the Managers suggestion made above.

However, this doesn't fit in with you requirement that they only get one shot at loading the user list.  Why do they only get one shot?

I suppose the simplest approach is just to have a simple query syntax like (-Cats;-Car) or perhaps (-All;+Cat;+Car).  This can be passed with the request to limit the data returned.

Ged Byrne
Thursday, June 19, 2003

"Why do they only get one shot?"

My guess would be to keep the interaction course grained. I have seen some initial naive fine grained distributed XML data passing architectures that of course went down flat on their bellies because of the enourmous latency introduced even at extremely light loads as a result of exessive sequential roundtripping across the wire.

Just me (Sir to you)
Thursday, June 19, 2003

We get only one shot at loading because we are on the other side of an soap interface.

When the xml get to the client side of the application the uses will use xslt to create their own front-end look. This actually works rather well, except for the problem with xml containing a lot of data there is no need for.

Trying to load the ekstra information while iterating through the list is both impossible in xslt and even if we where using jsp it would give to many soap connections.

Rasmus B.
Thursday, June 19, 2003

*  Recent Topics

*  Fog Creek Home