Let's continue...
--------------------------------------------------------------------------------
Chapter 11: Object-Oriented Programming (OOP)Much like a lighthouse is composed of modular systems—beacons, lenses, gears—object-oriented programming (OOP) lets you build applications as structured components. In Harbour, OOP empowers you to organize complex logic into reusable, maintainable, and scalable units.
This chapter introduces OOP in Harbour: defining classes, working with objects, encapsulating behavior, and extending functionality through inheritance and polymorphism.
---
1. Why Use OOP in Harbour?
Object-oriented programming brings several key benefits:
* Encapsulation: Group data and behavior
* Modularity: Divide large programs into small, reusable parts
* Inheritance: Share and extend logic easily
* Polymorphism: Interface flexibility across types
* Clarity: Clean separation of concerns
> Harbour’s OOP is dynamic, class-based, and fully integrated with the language's procedural core.
---
2. Defining a Class
Use the CLASS keyword to define an object with properties (fields) and methods (functions):
CLASS Customer
DATA Name INIT "Unknown"
DATA Email INIT ""
METHOD Greet()
ENDCLASS
METHOD Greet() CLASS Customer
? "Hello,", ::Name
RETURN
* DATA defines a property.
* METHOD defines a function tied to the class.
* :: refers to the current instance (similar to this in other languages).
---
3. Creating and Using Objects
Instantiate classes using :New():
PROCEDURE Main()
LOCAL oCust := Customer():New()
oCust:Name := "Alice"
oCust:Email := "
al...@example.com"
oCust:Greet()
RETURN
---
4. Constructors and Destructors
You can define a New() method for custom initialization.
METHOD New(cName, cEmail) CLASS Customer
::Name := cName
::Email := cEmail
RETURN Self
Usage:
LOCAL oCust := Customer():New("Bob", "
b...@example.com")
> Return Self so the constructor can be used inline.
---
5. Inheritance
Create a new class based on an existing one using the FROM keyword.
CLASS PremiumCustomer FROM Customer
DATA Points INIT 0
METHOD AddPoints(n)
METHOD Greet()
ENDCLASS
METHOD AddPoints(n) CLASS PremiumCustomer
::Points += n
RETURN
METHOD Greet() CLASS PremiumCustomer
? "Welcome back, premium user:", ::Name
RETURN
You can override parent methods to specialize behavior (polymorphism).
---
6. Polymorphism
Polymorphism allows you to call the same method on different classes.
FUNCTION SayHello(oAny)
oAny:Greet()
PROCEDURE Main()
LOCAL o1 := Customer():New("Joe", "
j...@x.com")
LOCAL o2 := PremiumCustomer():New("Anna", "
an...@x.com")
SayHello(o1) // uses Customer:Greet()
SayHello(o2) // uses PremiumCustomer:Greet()
RETURN
This makes your code extensible without changing the core logic.
---
7. Static and Class-Level Methods
Use CLASS FUNCTION for utility methods not tied to instances.
CLASS MathUtil
CLASS FUNCTION Square(n)
ENDCLASS
CLASS FUNCTION Square(n)
RETURN n * n
? MathUtil:Square(5) // 25
---
8. Visibility and Encapsulation
While Harbour does not enforce strict private/public visibility like some OOP languages, naming conventions and discipline help:
* Prefix internal fields with underscore: _nCount
* Avoid exposing internals unnecessarily
* Provide getters/setters if needed:
METHOD SetEmail(c) INLINE ::Email := Lower(c)
METHOD GetEmail() INLINE ::Email
---
9. Using Objects in Arrays or Hashes
Objects can be stored in collections like arrays or hashes.
LOCAL aCustomers := { Customer():New("Tom", "
t...@a.com"), ;
Customer():New("Sue", "
s...@b.com") }
FOR EACH oCust IN aCustomers
oCust:Greet()
NEXT
---
10. Class-Based Architecture Example
CLASS Product
DATA Name INIT ""
DATA Price INIT 0.0
METHOD New(cName, nPrice)
METHOD Display()
ENDCLASS
METHOD New(c, p) CLASS Product
::Name := c
::Price := p
RETURN Self
METHOD Display() CLASS Product
? "Product:", ::Name, "Price: $", ::Price
RETURN
Usage:
LOCAL o := Product():New("Laptop", 999.99)
o:Display()
---
11. Dynamic Objects and Extensibility
Harbour allows dynamic addition of methods and data at runtime using metaprogramming techniques (advanced topic).
o:NewMethod := {|| ? "I'm dynamic!" }
Eval(o:NewMethod)
---
12. Quick Reference
| Concept | Syntax Example |
| --------------- | ------------------------------------|
| Define class | CLASS MyClass ... ENDCLASS |
| Define property | DATA Name INIT "" |
| Define method | METHOD Hello() CLASS MyClass |
| Instantiate | o := MyClass():New() |
| Inheritance | CLASS Child FROM Parent |
| Access member | ::Name (within), o:Name (outside) |
| Static method | CLASS FUNCTION Utility() |
| Polymorphism | oAny:Greet() (dynamic dispatch) |---
Best Practices for OOP in Harbour* Keep classes focused (Single Responsibility Principle)
* Initialize all fields in New()
* Avoid deep inheritance trees
* Use polymorphism instead of conditionals when possible
* Document class APIs with comments and headers
---
Final ThoughtsWith object-oriented programming, you build software not just as instructions—but as intelligent, cooperative entities. Each class becomes a reliable part of the system, like a cog in the beacon’s machinery, contributing to a greater, maintainable whole.
You're no longer just scripting logic—you're crafting architecture.
-------------------------------------------------------------------------------------------------------