OOP Best Practices Part 2

  • Thread starter Thread starter vze1r2ht
  • Start date Start date
V

vze1r2ht

I read Sloans post in my last thread but I did not quite understand it.

I have written my own custom object BASED around sloans object that he
posted.

Can anyone answer the questions at
http://thedogsatonthemat.com/viewtopic.php?t=21 ?
(I put it in my forum so the code is cleaner. You can reply here
instead of on the forum).


I also have a question regarding static vs intiated DALS.
 
I read Sloans post in my last thread but I did not quite understand it.

I have written my own custom object BASED around sloans object that he
posted.

Can anyone answer the questions at
http://thedogsatonthemat.com/viewtopic.php?t=21 ?
(I put it in my forum so the code is cleaner. You can reply here
instead of on the forum).


I also have a question regarding static vs intiated DALS.
Couple of questions about this OOP design:

1) Is it really neccessary to have UserManager? Could I not integrate
UserManager methods/properties in the User >class or UserCollection class
(UsersForCar would probably go in class Car right?)? Would doing that ruin
proper OOP >design? Performance?

Yes. Seperation of concerns militates for seperating them. UserManager
contains all your grungy database code, and squarely in the "back end" of
your application. User and UserCollection are used across all tiers of your
application.
2) How about performance? When you get a Car's users, you hit the DB twice.
Once to get the User IDs for a car, >then the second to load each user. How
ever....I could instead load the user object and its properties directly
thing is....if I wanted to load One User >object only..then I would have to
write LoadData logic for the User object.

Managing performance is a challenge in this design, and it's another point
in favor of a consolidated data access layer (UserManager). In UserManager
you have the option of retrieving and updating related tables in optimized
ways, instead of always sending a single database query for each entity on
load an update.
3) Is this design good? It implements lazy load design for the Cars Users
property because it only loads if needed. >Would this be bad performance
wise vs SQL returning multiple result sets for multiple collection loading
(etc >UserCollection for cars)

You have to manage these tradeoffs based on the use cases for your different
objects.
4) When does these methods go?? Like should GetUsersForCar be in the
UserManager object or Car object???

Implemented in UserManager, invoked from Car perhaps.
5) Is there some parts I could centralize??

I don't understand what you mean.
6) Should ID (like User ID) be Id or ID? I know silly question and I know
the answer is Id...but I feel like using >ID. Bad Naming convention?

Personal preference.
I really like this idea of True OOP binding instead of DataTables/DataSets
but I'm really worried about performance >overall. The SQL Server will
prolly get hit bad if say 25 users were to load the car object and query
the Users >property (thats 25 x 2 = 50 hits compared to 25 hits with
DataTable) but I hate binding with the DataTable.

First, the typed DataSet avoids late binding, and has the integrated
TableAdapter framework, so it's quite attractive. But there's no reason why
your approach should suffer poor performance. The DataSet will have to
issue multiple SELECT's for multiple DataTables too.


IMO one of the most attractive features of your approach is that you can use
nullable types in your entities, and have excelent type-fidelity between
your entities and database tables.

David
 
Yes. Seperation of concerns militates for seperating them.
UserManager contains all your grungy database code, and squarely in
the "back end" of your application. User and UserCollection are used
across all tiers of your application.

I agree - basically what Dave is saying is that Users and UserCollections
maybe sent across a network to different locations. i.e. a web service
/remoting might return a UserCollection thus you don't want to put any DB
logic into the UserCollection object since it may not have access to the
DB.

Furthermore, centralizing your logic into a manager class allows you to
check for access security in one spot rather than across all your objects
(if you don't have access, you can't call getUsers) ; )
 
Your User object and your UserCollection object are the objects which should
be able to be passed around.... You don't want the baggage of the database
code following that around.
Thus the use of the UserManager class.

You should be able to create User's and UserCollection's without any
dependance upon the database.
It just so happens that one primary way to create them and use them it via
database access. But this isn't always the only way.
Thus the seperation of this code into its own class.

.........
//quote Is it really neccessary to have UserManager? // end quote
I have the same arguments with people I work with all the time.
Objects are a collection of properties/methods and sometimes Events. The
code which creates them from the db, does not need to be in the objects
themselves.
You're making a bad decision at the beginning of your design process if you
do so.

...

//quote
When you get a Car's users, you hit the DB twice. //end quote

You shouln't need to hit the db twice. You need to write a stored procedure
to bring back all germane data in one procedure.
Your issue is that you're using inline sql. Look at my post about a
multi-recordset stored procedure, and NextResult().


//quote
static class UserManager
{
public static UserCollection GetUsers()
{
UserCollection collection = new UserCollection();
string sql = "SELECT * FROM Users";
SqlDataReader reader = _dal.ExecuteReader(sql);
while(reader.Read())
{
User user = new User( Conversions.DBToInt(reader["userID"]) );
collection.Add(user);

}
return collection;
}
public static UserCollection GetUsersForCar()
{
//implement logic for Car's Users. Just like above.
}
}

//end quote


You have your datalayer and biz layer intertwined.
_dal is NOT your datalayer. It is a HELPER class, which you datalayer
should take advantage of, but it does NOT substitute for a DataLayer object.


You need to relook at my examples. You're making a common mistake of
intertwining biz and datalayer code.

There should be some object
Data.UserData
and all this thing does is return IDataReaders and DataSets.
THAT's ALL IT SHOULD DO. It can use your helper class , _dal, but it is its
own object.

The biz layer will instantiate, can call some method on the UserData object,
to get a IDataReader.

Then your .SerializeUsers (IDataReader idr) code will be called to create a
collection.

...


You keep taking the advice people are giving you , and then you try to
abbreviate it, take shortcuts.

We can lead you to water, but we can't make you drink.

..............

Fyi, I call strongly typed datasets, the "poor mans business objects". You
can use them, they're good, but it depends on what your building.
When I build a good sized architectural solution, I always prefer strong
objects and collectionbases over typed datasets.


The performance of using a IDataReader (to populate a custom collection)
over a dataset (typed or untyped) has always favored the IDataReader
approach in my tests.
Again, for good sized architecture solutions, this is a 'up front' decision
which pays dividends down the road.
If you ever have to go to remoting, you're already got well designed
classes/collectionbases to work from.



Thanks David, "Spam Catcher", and/or Bruno for your followup responses.

...
 
I'm not sure I still get it.

Could you provide a full example that is related to my example?
User/Car etc.

I really appreciat your help.
 
I will work up a NorthWind example over the next 2 days, and post it at my
blog (and the link here if I can find the post).

Check with me after 3 days. if its not there.

...
 
Ok thanks a bunch...just dont use the pubstitle metholody...its so
confusing.

I think a better would be UserCollection etc
 
I read Sloans post in my last thread but I did not quite understand it.

I have written my own custom object BASED around sloans object that he
posted.

Can anyone answer the questions at
http://thedogsatonthemat.com/viewtopic.php?t=21 ?
(I put it in my forum so the code is cleaner. You can reply here
instead of on the forum).


Regarding the UserManager question:

I would move the GetXXX functions into the corresponding classes. There's
also a question whether there isn't a Singleton hiding in there from the SQL
query it looks like there's only one user collection. Or are there more
tables or DBs? In that case perhaps a class that contains the DB access is
more appropriate.

Here's a link to part of the old Taligent C++/OO documentation ("Managers
are not objects"). I've never convinced myself that all managers are bad
objects but the fact that you already have doubts about the validity of the
UserManager you might get some ideas out of it:

http://www.cubik.org/mirrors/taligent/Docs/books/WM/WM_47.html#HEADING61

Also, the fact that your UserManger has only static methods indicates that
it is a namespace in disguise. But where does the _dal variable come from,
looks like a member but it is in a static function of a static class?

Andrew
 
http://spaces.msn.com/sholliday/ 5/24/2006 entry


a "PubsTitle" is simply a title in the pubs database.
Basically,
select * from pubs.dbo.titles .. each row from that query is a "PubsTitle"
And there was a PubsTitleCollection.
Yeah, it wasn't the best naming convention, but it wasn't ~that far fetched.


email me for my paypal account name, so you know where to put my consultant
fee (ha ha).

...
 
Back
Top