Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

The correct way to design a class... 4

Status
Not open for further replies.

SharkTooth

Programmer
Aug 12, 2004
29
US
We are learning how to do OOP and have a question that we have been debating. Hopefully you guys can clear this up for us.

I get customer data from the database and I want to populate the “Customer” object with the data from the database. I also want to use the “Customer” object to add customers to the database. What would be the best design? Should we have a method in the customer class that retrieves the data from the database or should we have some other class that loads the information into the object. Also should the property CountyCode (in the example below) actually validate itself by going to the database when it is set? I feel like there should be a better way.

This is what the class could look like:
Code:
public class Customer:User, IAddress{

	public Customer(string customerId){
		LoadCustomer(customerId){
}

public string CountryCode{
		get{return _countryCode;}
		set{
if(ValidateCountryCode(value))
_countryCode = value;
}else{
	throw(new Exception())
}
		}
}

void LoadCustomer(string customerId){
	// do database stuff
}

bool ValidateCountryCode(string countryCode){
	// do database stuff to validate countrycode
}
	... 
}
Is this good design?

Thanks for your thoughts!
 
<Should we have a method in the customer class that retrieves the data from the database or should we have some other class that loads the information into the object.
Although it's not quite clear what the role of your Customer class plays in your application, it seems clear that it does not play a pure data retrieval role. This class seems to represent a single instance of data retrieval, and there are many general routines (opening connections, validating security, whatever) that would have to be redundantly implemented in this context.

I would create a data object of some kind, with methods that this object would access to handle general routines. The more you can generalize out about data retrieval, the less you have to redundantly rewrite if you change your data processing structure.

<Also should the property Count[r]yCode (in the example below) actually validate itself by going to the database when it is set?

I would, assuming that validation had to do with things like constraints. Things like putting a numeral in the country code setting you might want to disable in your data entry object.

thread796-1114678 may give you some useful ideas.

HTH

Bob
 
Hi SharkTooth,
heres my take on it. It seems like your Customer suffers from anemia, lackING any true behavior that defines what customers are. Also, you have added to the uncohesiveness by bundling behavior, such as dataloading routines AND validation into the customer.

According to Eric Evans, Domain objects should be "Responsible for representing concepts of the business, information about the business situation, and business rules".

If you want to instantiate customer instances from a data source, make use of a CustomerFactory which can accept the paramaters to create the Customer in it's valid state.
Ex:
Customer aCustomer = CustomerFactory.New("Tom","Jones","555-5555");


OK, i also notice you're doing validation using a method ValidateCountryCode()...Have you thought about using immutable value-objects? Immutable objects represent primitive types such as a CountryCode, PhoneNumber, Age, ZipCode, FirstName etc and play it's own role in validation via it's parse/constructor method...

Ex: The primitive int has a parse method that parses a string and returns a new instance of a int.

int.Parse("45");

why is that any different from:
CountryCode.Parse("1033");


Here, the parse preforms internal validation, throwing an exception in cases where the invariants are violated. It encapsulates and prevents its own business logic from cluttering the Customer. The customer should be responsible for maintaining it's own invariants as well.

EdwardJS

 
<Have you thought about using immutable value-objects?
That's a good thought, Edward. I'd say it works quite well on validation issues that relate to the object and only the object. Validation issues that deal with constraining how ojbects interdepend would need to be handled at a higher level, of course. I'm mentioning this not as if you missed that, but so sharktooth will understand that there's more to a good validation design than what you've given.
 
Bob,
when yopu say "constraining how ojbects interdepend", what do you mean exactly?

EdwardJS
 
I think Bob means that objects should be self-contained, and not depend on other objects for their operation.

In practice, however, you often have helper classes, and that's OK as long as you understand the consequences.

Chip H.


____________________________________________________________________
Donate to Katrina relief:
If you want to get the best response to a question, please read FAQ222-2244 first
 
Yes, objects should be self-contained, and not depend on others. Obviously, objects DO have to depend on others to some degree, though: if an object supplies data to another object, the consumer will depend on that data to do its job. So, what chip is saying (I am too) is that objects should not be overly dependent on one another. Think of an object dependency as an investment in overhead.

However, also think of internal decision logic in an object as an investment in overhead. These two investments need to be balanced to minimize overhead. Do a search for "cohesion" and "coupling" to find more material on this site.

As for "constraining how ojbects interdepend", that isn't exactly what I meant here. I guess I was a little obscure. Objects do have associations, and those associations may have constraints. Validation rules that involve the state of multiple objects is what I meant by a constraint on how the objects interdepend.

For example, a car object may be an aggregate of several other objects: engine, two axles, 4 tires, and so on. The engine's accelerate method might need to check if there is air in the tires, that the wheel's brake property isn't set, and so on. Furthermore, a car's constructor might create a chassis, axles, and tires, and the restriction, say, of 4 and only 4 tires, that the tires must be in inventory, and so on, would also represent constraints on how they interdepend.

Perhaps your suggestion really covers these scenarios well as well. Maybe you'd like to expand on your answer.

Bob
 
OK! Here comes the theorist. My examples may be a bit odd, but the concepts are correct.

[blue]What validation can exist?[/blue]
At the screen level (and similarly at the datbase level, if you need it) validation comes in a gradation of types:
[ul]
[li]character level (was the fifth character either an 's' or a 'd'?)[/li]
[li]field level (was their age between 16 and 65?)[/li]
[li]form level (were all compulsory fields complete?) (was the total value less than the maximum allowable?)(if field x has value a, then field y should not have a value)[/li]
[li]data level (was the entered account number a valid account in the system?)[/li]
[/ul]
[blue]How should they be defined?[/blue]
These then can be distributed in the system. All the validations resulting from Business Rules should end up on the business classes. Within the business classes they end up in 5 places:
[ul]
[li]Class Constraints Often Form level Validation (if field x has value a, then field y should not have a value)[/li]
[li]Attribute Constraints Normally the Field level validation. (Age must be between 16 and 60)[/li]
[li]Method Pre-condition Now less tied to screen concepts. (Method can only be called if input value exists) [/li]
[li]Method Post-Condition Should an appropriate algoritm used (If the set of data had a standard deviation of greater than x, then the smoothing algorithm should be applied.) [/li]
[li]Association constraints (There MUST always be a team leader) (You cannot borrow more than three books from the library) (You cant have gynaecological results if you are male!)[/li]
[/ul]
[blue]Where should they be implemented?[/blue]
[li]Business Model Layer It is easiest and most 'cohesive' to perform much of the validation within the appropriate class. This is particularly true where the classes have a close association with the database tables, but should be considered the first stop.[/li]
[li]ControllerHowever, some of the more complex validations, involving more than one class may be carried our in the application controller, because that is what it does; it keeps classes from having to know details of other classes. [/li]
[li]User Interface Layer Then for speed of response at the screen, some of it can be carried out in the user interface. For example, testing the validity of every character in a field can only be sensibly done here, although a more sensible thing is to have less stupid fields.[/li]

Then along come the b****y programmers and stick in all sorts of helper classes, factories facades etc. Then it becomes more difficult to be so precise. However, the concepts are the same, but it just needs more work.

Gil
 
Outstanding, grooke. What I was talking about in your examples would be an "Association constraint." You've explained all this a lot better than I could have.

To round out your post, the last part doesn't seem to suggest that any validation ought to be carried out in the data layer. Personally, I can think of a number of things that I would put there, such as user authorization, whether a request for data returned any, and so on.
 
No! Not what I call the data layer. You have at least two actors in most systems: the user and the database . Both can trigger actions, respond to requests etc. This gives two structures sitting on top of the Business layer objects:
[ul]
[li]Actors:- User Database [/li]
[li]Interfaces:- GUI/UI . API [/li]
[li]Controllers:- Application Controller Data Controller [/li]
[li]Business Model:- Shared by the two sets of layers above.[/li]

[/ul]

The Data Controller is where you the users authorisation to manipulate data etc. It is also where you sort out checks on possible data problems etc. It manipulates the data interface rules, time outs, database indexes, views etc.

The Business Model Object knows just about its own business rules, which is largely validation and possible methods associated with a set of values.

The Application Controller is where the user's authorisation for this function within the system is checked. Also session management etc. However, another part of it knows about the 'Business Sequence' for calling the business objects, so that they do NOT need to have this multi-object knowledge; of course if they are closely related, one business object may elect to control his associates. This part, is sometimes made a sub-layer in some archtectures, but really just imposes the Use Case sequence on the Business Model objects.

Any way, I would put the validation in the Business Model and the data manipulation in the Data Controller.

Remembering our discussion in a previous thread; Is SQL in the data layer (I think so) or is it in the API?

Gil
 
Well, that rounds out your post. :) Microsoft describes their "3-tier" or "n-tier" in terms of the business layer as between the data and presentation (application controller?) layers, with presentation sitting on top of business sitting on top of data. Either way is probably valid. I see the business layer as brokering communication between data and presentation, applying business rules as it does so. Your application of use case terminology to the problem is interesting, too.

I'm not sure I agree with putting user authorization for a function entirely in the application controller. It seems to me that user authorization is a process that pertains more to the data itself than the application requesting the authorization. I think of it as two objects in association with one another: a session object instantiated by the application controller, which requests authorization of an authorization object instantiated in the data controller. The latter would throw an exception to the former if there were a problem with authorization. I see it this way because the process of authorization is specific to a given data repository, rather than to a given application accessing same. If you change the data repository, you change the way you access security.

We may be saying the same thing, of course, in different ways. :)

As for your last two sentences: I would too. I think so too.

Bob
 
<I'm not sure I agree with putting user authorization for a function entirely in the application controller.
Reading back on this, it seems I didn't read grooke's last quite as carefully as I should have, since that's not what he was suggesting. Of course, there may be processes of authorization within the context of the system at hand as well. My thinking was that authorization parameters are stored somewhere as data, so they're part of the data context. However, there would also most likely be things such as different sorts of groups being allowed into different contexts in the system, and those might very well be checked independently of the data. For example, when userA logs in, we go to the data and find that userA has data entry privileges and not admin privileges. However, if userA then tries to do something in the system that requires admin privileges, it's the system context that would evaluate userA's privileges and prevent access.
 
Yeh! I probably simplified here.

Normally, a user has a set of roles or authorities that are used to control what they can or cannot do. One of these tends to be global, allowing them access to your program. When they log on, the system tends to down load this data from LDAP or some other system files and make it readily available to the program. This tends to happen in a 'Session Layer' somewhere below the User Interface layer and above the Application layer. This is where a user is or is NOT given the 'Adminstrator' authority.

If the system allows specific access to one function and not others, then you also need access tables associated with each function (use case) or each set of business tables (classes); note, I said 'set'. These table identify what user roles or authorities you need to have to perform that functionality or to access that data. The functional ones tend to lie at the bottom of the application layer. This is normally where the 'Administrator' authority would be checked.

The data ones tend to lie in the business classes somewhere; depends on the structure of the application. These tend to be 'Can see Salary' or 'Supervisor' type of previleges. They could be constraints (business rules) on the attribute or on the function that displays the data.

So yes! I only went for the first half of the problem. Bob was quite right.

Gil
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top