Page 1 of 1

Accessing other Same-Level Objects

Posted: Thu May 12, 2005 6:09 pm
by Ambush Commander
The title's a bit obtuse, so I'll try to explain.

Let's consider a database system where we have an author: this author is represented by the class TWP_Data_User_Author. Inside, we have an array of TWP_Data_Story objects (which each have TWP_Data_Chapter objects in them). The Author object contains information about the author, such as Real Name, email address, etc.

Let us consider we have another type of class: TWP_Data_User_Project. This is a project that people can participate in: it's sorta like an author, but has many differences.

Our TWP_Data_User_Author "bob" has participated in TWP_Data_User_Project "wikipedia". His author page will display some relevant information about TWP_Data_User_Project.

The question, now, is where we put the TWP_Data_User_Project.

Currently, the main object is TWP_Data_User_Author "bob", and that's the basis of the page display. In order to grab information about TWP_Data_User_Project while using methods inside TWP_Data_User_Author, we could store the project in a variable in the object, like: $this->project_object

However, there are also project pages, which display information about the authors who have participated in this project. If we were to follow similar logic, there would be a $this->author_object variable. As you can see, this could lead to infinite recursion.

When you use an object, it may need to access the information of another object: but when this object is not clearly within it's hierarchy, trying to put it as a lower-level object will cause organization problems. This means:

Code: Select all

Rule: Author contains Project
Rule: Project contains Author
Author contains {Project contains {Author contains ...}}
It doesn't make sense, and it the fix is ugly (probably involves passing a variable stating how many times you should recurse through the object)

But does this mean we create a global object that contains all the Author and Project objects? And if that's the case, how would an Author object access information from a Project by using one of it's own methods?

Obviously, $this->project won't work. Is it possible using only Author's methods? Does this mean interobject methods have to be stored independent of the Author and Project objects?

I'm a bit confused, but this seems like a kind of question that has been addressed in past programs. What is the correct design for this sort of situation?

Posted: Mon May 16, 2005 5:49 pm
by McGruff
It might help to stop thinking about the data. Instead think about the domain layer: try and identify discrete roles and write lean classes which do just one thing - "do-ers" rather than nouns.

Posted: Mon May 16, 2005 5:54 pm
by Ambush Commander
Well, what I want to do is have the object represent the data, and I want it to do all the populating too, a sort-of integrated mapper class. Then, the program just accesses the values it needs from the object.

Maybe I should seperate the Mapper to another class?

Posted: Mon May 16, 2005 7:54 pm
by McGruff
OK so this is more an object-relational mapping problem? I can't recommend Martin Fowler's Patterns of Enterprise Application architecture too highly (a taster here). It's essential reading for all programmers. He's very lucid on general design issues and there's a lot in the book about O/R. I've never had to create anything too complicated so I'm not sure if I can help much with the more complex database stuff.

Posted: Mon May 16, 2005 8:06 pm
by Ambush Commander
Well, it's not exactly the mapping for Databases, because I was planning on building the interface before the mapping. I currently have this really inefficient system for storing data, and I'm going to port it to MySQL, but first, I wanted to redesign the way I accessed the data.

So, I started coding an Author class that you could initialize by an id and then would make a query to the original "database" and fill up the entries. This was all fine and dandy until I realized that I also needed to access other "objects" (as I mentioned earlier). I, personally, don't think there's anything complicated about it. :oops:

Wait... this may be a problem with external data caching. If you have a object that needs to be aware of ten other objects, the best solution probably isn't to initialize those objects every time you need to handle this one object, instead, store cached information in that single object of what you need. Is that correct?

Posted: Mon May 16, 2005 8:27 pm
by McGruff
I'm not sure I really understand the problem well enough but as you say maybe you could try to design the classes so that, in each request, only the objects you really need are invoked.

Posted: Mon May 16, 2005 8:31 pm
by Ambush Commander
Well, say you have a project with 50 members. Obviously, you don't want to invoke all 50 member objects.

Ugh... how to explain?

Posted: Mon Jul 25, 2005 8:00 am
by fastfingertips
As you may notice you will make an UML or just try to make a database design you will notice that there is an n-n relation, so you will need additional information in order to get lets say history of all users from a project;

instead to set

Code: Select all

$this->_intProjectId = 1;
try to add additional details

Code: Select all

$this->_intProjectId = 1;
$this->_intProjectMembet = 2;
and to your method send this two properties instead of one :)

Posted: Mon Jul 25, 2005 11:28 am
by Ambush Commander
I'm not sure I exactly understand what you're saying, could you explain more clearly?

I've been reading up on SQL recently, however, and I'm thinking the best way to resolve this issue is just to not to pass things around hierarchally. Allowing information that would have been queried for unrelated functions to be used again is just information caching, and that can be handled with its own framework.

Posted: Mon Jul 25, 2005 11:33 am
by timvw
Meaby you want to have a look at http://www.ezpdo.net...

Posted: Mon Jul 25, 2005 12:01 pm
by Ambush Commander
PHP4, unfortuantely. I'll though I will take a look.

Posted: Mon Jul 25, 2005 12:34 pm
by nielsene
Perhaps you want to look at doing lazy initialization.

For instance the author doesn't fetch the data until the "get" method. Then creating a container with lots of Authors isn't a huge upfront cost. You'll still have to load all the data eventually, but it might save some.

Then if preformence dictates it later, you could potentally implement a bulk loader in the collection class that could use a more efficient query, etc.

I personally would like to keep my objects as lightweight as possible, so I don't mind having large collections/iterations on them. Thus a lazy initialization paradigm tends to help.

Posted: Mon Jul 25, 2005 1:41 pm
by Ambush Commander
That sounds about right. It means that I'd have to make functions for accessing all variables, but it's not that unreasonable. Plus, even if you load the data, the Project doesn't need all the information about the authors, just some of it, so lazy initialization means that some of the information is retrieved, not all of it, and you still get to use the same object class.

Posted: Mon Jul 25, 2005 1:45 pm
by nielsene
Yes, but also when dealing with the DB, you don't want to do too many small queries. So, on the first request for data from an Author, I'ld probably pull in most of the referenced data.

Ie the real name is requested, I'ld pull in Email, etc as well.
I'ld probably pull in the list of IDs for projects, but not the contents of said project, etc.

You don't want to do multiple queries like
"SELECT realname FROM authors WHERE authorid=foo"
"SELECT email FROM authors WHERE authorid=foo"...

It has to come down to some decisions on "heaviness" of instantiation and common use patterns.