Hello xProgrammer,

On Mar 16, 2010, at 4:56 PM, [email protected] wrote:

> Hi all
> 
> Its nice to see that a discussion that started out with some highly
> questionable
> assertions about OOP has turned right around to a discussion of ORMs
> which 
> essentially extend the OOP concept.
> 
> Harbour doesn't force OOP on anyone, but I suspect most savvy xBase
> coders head 
> that way.  Even those that write procedural code are using some objects,
> hidden from them by the preprocessor.  Beginners soon realise that they
> are
> writing code that pretty much does something similar to what they have
> done
> before.  At first they may use the "cut and paste" approach.  Most then
> come to 
> realise that this approach is not ideal because
> 
> 1. Its easy to miss bits of code that need to be altered
> 
> 2. To change "standard behaviour" you have to change code in many places
> 
> So most of us ended up with a whole series of "utility functions" which
> identified (as parameters) those things that changed from invocation to
> invocation and meant that standard behaviour could be changed by altering
> a
> single piece of code.
> 
> OOP basically extends this in a more powerful and consistent way.
> 
> But if you don't like writing "standard" Harbour OOP code that might look
> like
> 
> obj_MyWindow := TWindow():New( 500, 300, "Sample Window" )
> 
> you can use the preprocessor and write something like
> 
> CREATE WINDOW myWindow TITLE "Sample Window" SIZE 500, 300
> 
> all it takes is a preprocessor directive like
> 
> #xcommand CREATE WINDOW  TITLE  SIZE ,  => ;
>  := TWindow():New( , ,  )
> 
> That is one of the fundamental beauties of xBase.
> 
> I would also note that the popularity of VB is due to Microsoft's
> marketing power and the fact
> that many of us are effectively forced to use it (or its sibling VBA) to
> automate office type tasks.
> If you judged languages by their popularity you wouldn't be using Harbour
> despite the fact
> that its so wonderful a language.
> 
> Now onto the interesting part - ORMs.
> 
> These should fit very neatly into Harbour.  Take an "example" from a 
> previous post:
> 
> emp=Employee.new
> emp.name = "Emp1"
> emp.basic = 4500
> emp.designation = "Programmer"
> emp.save
> 
> Harbour equivalents are easy:
> 
> obj_Employee := TEmployee():New()
> WITH OBJECT obj_Employee
>   :Name := "Emp1"
>   :Basic := 4500
>   :Designation := "Programmer"
>   :Save()
> END
> 
> Of course there are many alternatives (depending in part on the TEmployee
> class) such as
> 
> obj_Employee := TEmployeeNew( "Emp1", 4500, "Programmer" )
> obj_Employee:Save()
> 
> Or with suitable preprocessor directive for those that like the object
> orientation hidden
> 
> CREATE EMPLOYEE ThisEmployee
> ThisEmployee:Name := "Emp1"
> ThisEmployee:Basic := 4500
> ThisEmployee:Designation := Programmer
> SAVE EMPLOYEE ThisEmployee
> 
> Obviously we have to define the TEmployee Class which would inherit from
> a class that
> "understands" how to read / write etc but not the particular details of
> an employee record,
> something like:
> 
> CLASS TEmployee FROM TSingleRecord
> 
>   DATA Name
>   DATA Basic
>   DATA Designation
>   // etc
> 
> ENDCLASS
> 
> Methods like Save() would be inherited from TSingleRecord as might its
> oid (object 
> identifier / primary key )

Exactly.

> 
> CLASS TSingleRecord
> 
>   DATA oid
>   // etc
> 
>   METHOD Save()
>   // etc
> 
> ENDCLASS
> 
> This is very much along the lines of the approach I use combined with a
> client-server data 
> base back end I wrote for my own use.  A record is returned as a
> two-dimensional array that
> can be used to directly update the front end object.  The array is
> serialsed and transmitted
> using IP sockets.  Properties are directly updated using
> __ObjSetValueList().  This type of
> approach would seem ideal for an ORM in my opinion.

I'll add that to fulfill this approach, we need to have at least:

  * Abstraction
  * Inheritance
  * Polymorphism

e.g., The following sample creates  three new databases:
  TEmployer 
  TPerson
  TEmployee

fills the databases with some values and then prints it out:

<prg>
/* Contains the Employer's database */
CLASS TEmployer FROM TTable
  DATA tableName INIT "employer" // the physical file data base
  DEFINE FIELDS  // Load the Field's information
ENDCLASS

BEGIN FIELDS CLASS TEmployer

  /* the primary key database */
  ADD PRIMARYKEY FIELD "Employer" AUTOINCREMENTAL
        
  ADD STRING FIELD "FirstName" SIZE 100

  ADD STRING FIELD "LastName" SIZE 100
        
  ADD STRING "Phone" SIZE 40

  /* creates a TEmployees table whos MasterSource
     is this database (TEmployer) */
  ADD OBJECT FIELD "Employees" CLASS "TEmployee"

END FIELDS

/* Contains the Person's database */
CLASS TPerson FROM TTable
  DATA tableName INIT "persemp" // the physical file data base

  DEFINE FIELDS // Load the Field's information
        
  /* calculated fields */
  CALCFIELD Age INLINE Years( ::Field_Birth )
  CALCFIELD FullName INLINE RTrim( ::Field_LastName ) + ", " + RTrim( 
::Field_FirstName )
        
ENDCLASS

BEGIN FIELDS CLASS TPerson

  /* the primary key database */
  ADD PRIMARYKEY FIELD "Person" AUTOINCREMENTAL

  ADD STRING FIELD "FirstName" SIZE 40

  ADD DATE FIELD "Birth" ;
    VALID {|d| Year( d ) > 1850 } /* validation for field */

  ADD STRING FIELD "Genre" ;
    VALID {|g| g $ "FM" } /* validation for field */

END FIELDS

/* Contains the Employee's database */
CLASS TEmployee FROM TPerson
  DEFINE FIELDS // Load the Field's information
  CALCFIELD Age INLINE Years( ::Field_HiredOn )
ENDCLASS

BEGIN FIELDS CLASS TEmployee

  /* the master key database */
  ADD OBJECT FIELD "Employer" CLASS "TEmployer" MASTERKEY

  ADD FLOAT FIELD "Salary" ;
    VALID {|s| s >= 0 } /* validation for field */
                
  ADD DATE FIELD "HiredOn" ;
    VALID {|d| Year( d ) > 1850 } /* validation for field */

  /* the primary key database */
  ADD PRIMARYKEY FIELD "Person"
                
END FIELDS


FUNCTION Main()

  emp := TEmployer():New()
  
  /* adds a new TEmployer record */
  emp:NewRecord()
  
  emp:Field_Name := "US ROBOTICS"
  emp:Field_Phone := "1 555 555555"
  
  /* adds a new TEmployee record */
  emp:Field_Employees:NewRecord()

  emp:Field_Employees:Field_FirstName := "John"
  emp:Field_Employees:Field_LastName := "A"
  emp:Field_Employees:Field_Birth := "1/1/1970"
  emp:Field_Employees:Field_HiredOn := "1/1/2000"
  emp:Field_Employees:Field_Genre := "M"
  emp:Field_Employees:Field_Salary := 80000

  emp:Field_Employees:Post()
  

  pers := TPerson():New()
  
  /* adds a new TPerson record */
  pers:NewRecord()

  pers:Field_FirstName := "Jane"
  pers:Field_LastName := "B"
  pers:Field_Birth := "1/1/1980"
  pers:Field_Genre := "F"

  pers:Post()
  
  /* adds the previous TPerson record to TEmployer */
  emp:Field_Employees:NewRecordFrom( pers )

  emp:Field_Employees:Field_Salary := 80000
  emp:Field_Employees:Field_HiredOn := "1/1/2000"

  emp:Field_Employees:Post()

  /* prints the whole TEmployer database with his employees */
  WHILE !emp:Eof()
    ? "Employer: ", emp:Field_Name, emp:Field_Phone
      WHILE !emp:Field_Employees:Eof()
        ? "  Employee:"
        ? "     Genre:", emp:Field_Employees:Field_Genre
        ? "  FullName:", emp:Field_Employees:Field_FullName
        ? "       Age:", emp:Field_Employees:Field_Age
        ? "    Salary:", emp:Field_Employees:Field_Salary
        emp:Field_Employees:Skip()
      ENDDO
    emp:Skip()
  ENDDO

RETURN NIL
</prg>


best regards,

Teo


_______________________________________________
Harbour-users mailing list (attachment size limit: 40KB)
[email protected]
http://lists.harbour-project.org/mailman/listinfo/harbour-users

Reply via email to