www.luntacunt.fora.pl

Luntacunt project

www.luntacunt.fora.pl Forum Index -> Snapshots -> Simple Object Relationships
Post new topic  Reply to topic View previous topic :: View next topic 
Simple Object Relationships
PostPosted: Wed 0:35, 04 Sep 2013
cheapbag214s

 
Joined: 27 Jun 2013
Posts: 20570
Read: 0 topics

Warns: 0/5
Location: England





Simple Object Relationships,[link widoczny dla zalogowanych]
In the last article we looked at how the classic Stock, Order and Customer requirement could be modelled as three separate business objects, each exposing their state through welldefined properties. Although these objects could now be used asis (although in a very limited way we haven't yet defined how to make their information persistent!), they lack any concept of relationships. In other words, how do we know which Customer placed a given Order, and for which StockItem?
It is illuminating at this stage to pause and think about how this would traditionally be handled in a nonOO, datacentric fashion. Typically, a database record representing the Order would expose two additional fields, one storing a foreign key to the Customer table, and another to the StockItem table. One of the deficiencies of this approach has already been demonstrated: all database fields are exposed to the same degree; there is no concept of one field being more "private" than another. Of course, it is possible to express this to a certain extent with a database view, but at the raw data level fields cannot be distinguished in terms of visibility or role except by name, and that way madness lies.
Let us now consider how we would access information about the customer who placed a given order in this traditional model. Assuming we have got the information about the order in some kind of dataset (maybe a TQuery), we would inspect the value of the customer foreign key field, construct a new query selecting from the Customer table based on this value, and then inspect the data returned. Note that this is actually quite a lot of code to write, requiring at least one local object (the customer dataset) to be constructed, and such code quickly proliferates if we need to access the stock item or other related data items. An alternative to this approach is to select all of the data in a single query using a multitable join. This overcomes the amount of code to be written but introduces another issue the hard coding of the data relationships within the query string. In anything other than a trivial application such expressions are repeated in many different places throughout the source and it is worth noting that the compiler can do nothing to assist in the correctness of such queries. If you change database fundamentals (perhaps changing the name or type of the foreign key field in a table) then it is necessary to resort to applicationwide search and replace techniques to find occurrences which might need updating. In this situation it is very possible that some infrequently accessed form will be fall through the net and will retain an out of date reference to a field that no longer exists. This is a runtime error waiting to happen. It is possible to place such these queries in a centralised data module but that's just geography,[link widoczny dla zalogowanych], and requires care so that two separate parts of the application don't attempt to use the same query concurrently.
Back in the orderly world of wellconstructed business objects exposing the equivalent of a foreign key (in the form of our TObjectID) as a public property is anathema. Listing 1 shows how this would look and a quick glance shows that we have adulterated our public interface with details that we'd rather not expose. After all, if such properties are made public then everyone can assume that they have the right to use them.
Object orientation offers us a far more natural way of expressing these relationships rather than through implicit foreign key fields we can actually expose the related object as a property. Note that this is a natural and concise way of expressing the relationships and completely hides the implementation details. It is worth pointing out that if we later decide to remove the Company relationship (or, indeed, change the way in which it is implemented), then the compiler will detect every instance throughout the application where it is being used incorrectly, and the compile will fail until all issues are addressed. Already object orientation has assisted us to help deliver a more reliable application: we can make assertions about the fact that all relevant changes have been made.
Assuming we are going to expose our related objects as properties, how is this going to be implemented? Obviously, we are going to need to a private "placeholder" field to store a reference to the related object. A nave approach would be to create this related object in the constructor and simply have the property pointing to the private field. This approach has two main issues one undesirable and the other catastrophic. The undesirable issue is that we are going to incur the burden of constructing this related object every time we construct the parent. Assuming we populate the properties of the related object from persistent storage, we have impacted the runtime performance of our application with the overhead of constructing a new instance and making a database access. In general, it is worthwhile taking some care to keep the constructor as lightweight as possible. Extending this situation, it can be seen that if constructing object A causes the instantiation of object B, whose own constructor causes the instantiation of the same object A then we are going to enter the world of infinite recursion and the first thing a user will see is an out of memory error message. This situation is no more than the very common 11 entity relationship.
The solution to this issue is a technique known as construct on demand,[link widoczny dla zalogowanych], or lazy construction. This uses the idea of delaying construction of the object until just before the first time it is required. For future accesses the already instantiated object is simply returned. This delays any expensive operations until the last possible moment, while remaining transparent to all users of our class. Listing 2 shows how this can be implemented. For the time being,[link widoczny dla zalogowanych], we will assume that all of our TPDObjects offer a Load method that populates the object properties from some kind of persistent storage, given a relevant unique object ID.
Leveraging the power of objects
This appears to solve our problem of cascading construction,[link widoczny dla zalogowanych], and is a technique that can be used to great effect with any property (not just business objects) that is potentially expensive to construct. However, let us think about what will happen when we apply this technique to other business objects. Rather than repeat such similar code (and run the risk of not implementing all such accessor functions identically), is there any way in which we can use the power of our object hierarchy to reduce this coding burden? Unsurprisingly,[link widoczny dla zalogowanych], the answer is an emphatic yes.
What we would like to do is to provide some kind of utility function in our base TPDObject class (part of our applicationindependent framework) which performs the same function but can be parameterised in some way. The salient details that we will need to pass as parameters are the placeholder for the object being constructed, the ID that should be loaded,[link widoczny dla zalogowanych], and some way of constructing the correct class. To achieve this last parameter we will use a construct called a class reference, which is a variable that holds a specific type as part of a class hierarchy. In Delphi, this is defined with the class of keyword. Listing 3 shows the changes to our Framework unit to provide such functionality. Note that the object instance will actually be updated in the routine and this is therefore one of the few occasions where an object should be passed as a var parameter.
One other element of note is that the constructor for TPDObject has now been defined as virtual. Without this our generic routine would not be able to call a specific class constructor, and would always construct classes of type TPDObject. This is the same approach as is used for components within Delphi,[link widoczny dla zalogowanych], and the consequence is the same: all of our constructors for our TPDObject descendants must now use the override keyword.
How will our accessor functions on our business objects now use this available method? Their interfaces must remain the same, parameterless. However, we can implement the call in a single line of code as shown in Listing 4. Two factors should be highlighted: the result of the call must be typecast to TCustomer as it returns a type TPDObject, although the actual instance will be of the correct type. Secondly, the private FCustomer field must be changed to type TPDObject. This is because Delphi insists that var parameters are exactly the expected type. In both cases these are safe operations as the details are private and we are guaranteed to be returned a class of the expected type, even if the ancestor class has no knowledge of them. We are now able to implement all such relationships in one line of code,[link widoczny dla zalogowanych], using a centralised applicationindependent routine. The benefits of a true OO development are beginning to make themselves known. Having constructed these related business objects, we must ensure that they are destroyed. A simple approach is to place standard calls to Free in the destructor: the protection around Free will ensure that nothing untoward will happen if the object has not actually been constructed (Free on a nil object is an allowable operation).
Previously I alluded to the set of classes that should not be used in a "true" OO application. Figure 1 from last month's column shows that interface elements cannot interact with the persistence layer, only the problem domain. Dataaware components break this rule,[link widoczny dla zalogowanych], sending changes directly to the database connection, and therefore (controversially) should not be used. There are many, better, alternatives and these will investigated in future columns.
相关的主题文章:


[link widoczny dla zalogowanych]

[link widoczny dla zalogowanych]

[link widoczny dla zalogowanych]

[link widoczny dla zalogowanych]

[link widoczny dla zalogowanych]

[link widoczny dla zalogowanych]

[link widoczny dla zalogowanych]

[link widoczny dla zalogowanych]

[link widoczny dla zalogowanych]

[link widoczny dla zalogowanych]


The post has been approved 0 times
View user's profile
Simple Object Relationships
www.luntacunt.fora.pl Forum Index -> Snapshots
You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
All times are GMT + 2 Hours  
Page 1 of 1  

  
  
 Post new topic  Reply to topic  


fora.pl - załóż własne forum dyskusyjne za darmo
Powered by phpBB © 2001-2003 phpBB Group
Theme created by Vjacheslav Trushkin
Regulamin