Doug,
>>> I take your point about "scatter / gather" but please note that scatter/gather could be implemented in my architecture (not subclassing xDATAFILE class but merely pointing to it) equally as in your architecture.
>> I'm sure it could be, but it requires lots of coding--and it seems that you would need to hand code it for each class. If you use TDatabase or TData, there is no coding required.
>No - only once - in xDATAFILE
Hmm, can you show us a small example? I am having a hard time seeing how you could write a generic gather/scatter routine. I would think that you would have to create data elements for each fieldname and assign them in both the gather and scatter methods and this would have to be done for each class. And you would have to define all the data elements in the table class also.
- Code: Select all Expand view
method load() Class TPatientList
::name:= ::cAlias->PT_NAME
::city:= ::cAlias->PT_CITY
return nil
method load() Class TPatient
::name:= ::oPatientList:name
::city:= ::oPatientList:city
return nil
With TDatabase and TData fieldname are automatically generated as DATA so you can do:
oPatientList:= TData():new(,"patients")
oPatientList:use()
msgInfo( oPatientList:name ) // returns James
And then you can change the data in the name var:
oPatientList:name:= "Doug"
msgInfo( oPatientList:name ) // returns Doug
This buffered data, the disk record still contains "James" until you do a save(). So you can use these in controls and if the user selects OK you do a oPatientList:save() otherwise you do nothing and the disk record remains as it was.
Note that there were only two lines of code needed to get this object by using the generic TData class. We can use the same code and only change the filename to get a different object and it knows all the fieldnames of that database.
oOrderList:= TData():new(,"orders")
oOrderList:use()
msgInfo( oOrderList:orderID )
A subclass for a patientlist class could be as simple as:
- Code: Select all Expand view
class TPatientList from TData
method new()
endclass
method new() class TPatientlist
super():new(,"patients")
if ::use()
::setOrder(1)
::gotop()
endif
return self
Then you can do:
oPatientList:= TPatientlist():new()
msgInfo( oPatientlist:name )
>> Additionally, reading and writing only certain fields means that you have to have different load and save methods for each situation. This violates the polymorphism rule of OOP. You can't just call oObject:load() you have to use oObject:load1(), oObject:load2(), etc. depending on the situation. So you can't do generic things like pass any object to a function.
>It doesn't stop you from having a generic oObject:load(). But if you truly followed that mantra you couldn't possibly write any system with any level of complexity using SQL if you wanted any reasonable level of performance.
If you use a TRecordset class then you can select whatever fields you wish:
oPatientList := TRecordset():new( "SELECT name, city FROM Patientlist , "Provider=Microsoft.Jet.OleDB.4.0;Data Source=Northwind.mdb" )
oPatientList:city:="San Francisco"
oPatientList:save()
The recordset contains only the fields you specify and the save() method only updates those fields. Again here we have used nothing but a generic TRecordset class.
...
>In effect we are doing the same thing only you are using subclassing as a mechanism, I am using pointers to other objects as my preferred mechanism. I think mine is cleaner, more flexible, more transportable and more reflective of the real world. You may well think otherwise, but in reality the difference either way is small.
OK. However, I am still having a hard time grasping your design.
>But I don't like to encourage people to think in terms of data files rather than objects which I think subclassing most objects from a data file class may do in the case of people less experienced than yourself.
I agree with you and I did discuss this in one of the articles on my website. There is a difference between a patient object and a patient table. I have not discussed this much on the forum because I have a hard enough time getting others interested in using OOP without confusing them too much.
>> My concern is still that you don't fully understand OOP and as a consequence you are making much more work for yourself.
>I think you may have misjudged me based on my decision not to do automated scatter/gather and to write my own xDATAFILE Class. Both were conscious decisions and neither really justify your conclusion.
OK, are you saying that you are having to write more code but you think it is worth it, or are you saying the you don't have to write more code with your design?
>I would like to repeat that a patient (represented by an object of class PATIENT) is not an example / subclass / whatever of a data table record (represented by part of an object of type xDATAFILE) although there is clearly a correlation between them. Furthermore a list of patients is a different object from a single patient and I believe should be different classes. If they are in the one and the same class you would, it seems to me, be in flagrant contradiction of your own polymorphism mantra - what does oObject:load() do - load one or load a list?
As with other code there are tradeoffs. I also have a TRecord class which I use as the base of a TPatient class.
oPatientList:= TData():new(,"patients")
oPatientList:use()
msgInfo( oPatientList:name )
Or you can do (in addition to the above):
oPatient:= TRecord():new( oPatientList )
msgInfo( oPatient:name )
For some routines it is just faster to use the table class only.
The generic TRecord class only has new(), load(), save(), and end() methods. It also automatically adds all the fieldnames as DATA. Normally, I would subclass this and add any methods specific to a patient, like age() for instance.
Like yours, my patient class would contain in instance of the patient table. The patient object reads and writes its data to the table object. The big difference is that mine automatically generates fieldnames as DATA and they are buffered. This is inherited.
You could have an instance of a record class in the table class but I fear it would slow it down when you are doing browses and reports. Is this how you are doing them?
>Using classes and inheritance gives a range of advantages. True they can cut coding and solve problems of variable "life" (sorry - can't remember technical term) largely removing the need for public variables. And you have obviously fervently used them for these purposes. But there is also another aspect as to how they relate to their counterparts in the real world and maybe you aren't seeing their full potential in that regard.
Yes, I don't use any publics. And I do design my objects based real-world objects--I am a big advocate of doing this. Glad to hear that you are also.
Are you saying you never use inheritance?
Regards,
James