Plateforme Level Extreme
Abonnement
Profil corporatif
Produits & Services
Support
Légal
English
Defining Methods in Classes for Objects Added at Runtime
Message
De
20/02/2006 11:04:19
 
 
À
20/02/2006 05:06:15
Information générale
Forum:
Visual FoxPro
Catégorie:
Classes - VCX
Versions des environnements
Visual FoxPro:
VFP 9 SP1
OS:
Windows XP SP2
Network:
Windows XP
Database:
Visual FoxPro
Divers
Thread ID:
01096949
Message ID:
01097524
Vues:
18
Viv,

>
I think this is what I don't really understand. To me it sounds as if what you are attempting is NOT good OOP practice - encapsulation goes out the window to start with? You mentioned elsewhere the language you've previously been using that allowed this functionality; I know of none. Can you give a (pseudo-code) example of how this was being used in practice?
>

Consider the following scenario:
define class EXPANDER as CONTAINER

   ...

   procedure init
      this.addobject('some_label', 'LABEL')
   endproc

enddefine
Now consider the following:
define class EXPANDER as CONTAINER

   add object some_label as LABEL noinit

   procedure init
      ...   
   endproc

enddefine
First, these two scenarios are handled differently by VFP: they're not equivalent, and yet they should be. Now, suppose I wish to define the click event for the label, like this:
define class EXPANDER as CONTAINER

   add object some_label as LABEL noinit

   procedure init
      ...
   endproc

   procedure some_label.click
      ? chr(7)
   endproc

enddefine
VFP has no problem with this. Now, this isn't really poor OOP technique, but there are better ways to handle this. Eiffel, for example, supports multiple inheritance, generic parameters, and agents, any one of which could be employed in these circumstances depending on design requirements. Strong typing, however, is prerequisite to all of them, and VFP doesn't offer that either.

If you try to define procedure some_label.click in the former scenario, on the other hand, VFP will complain. Why? What's the difference? I have provided the code below from Eiffel showing the way this is handled in a pure and formal OOP environment. I generated the code from EiffelBuild, the equivalent of the Visual component of FoxPro. The "form" I designed was a simple window with a label in it (all of the comments are added by the code generator). I called the label 'first_label':


indexing
description: "Objects that represent an EV_TITLED_WINDOW.
The original version of this class was generated by EiffelBuild."
date: "Date: 2003/09/11 21:03:35"
revision: "Revision: 1.7"

deferred class
MAIN_WINDOW_IMP

inherit
EV_TITLED_WINDOW
redefine
initialize, is_in_default_state
end

-- This class is the implementation of an EV_TITLED_WINDOW generated by EiffelBuild.
-- You should not modify this code by hand, as it will be re-generated every time
-- modifications are made to the project.

feature {NONE}-- Initialization

initialize is
-- Initialize `Current'.
do
Precursor {EV_TITLED_WINDOW}

-- Create all widgets.
create first_label

-- Build_widget_structure.
extend (first_label)

set_title ("Display window")

--Connect events.
first_label.pointer_enter_actions.extend (agent mouse_enter)
-- Close the application when an interface close
-- request is recieved on `Current'. i.e. the cross is clicked.

-- Call `user_initialization'.
user_initialization
end

feature -- Access

first_label: EV_LABEL

feature {NONE} -- Implementation

is_in_default_state: BOOLEAN is
-- Is `Current' in its default state?
do
-- Re-implement if you wish to enable checking
-- for `Current'.
Result := True
end

user_initialization is
-- Feature for custom initialization, called at end of `initialize'.
deferred
end

mouse_enter is
-- Called by `pointer_enter_actions' of `first_label'.
deferred
end


end -- class MAIN_WINDOW_IMP

The initialize method creates the label and adds it (extend) to a collection of elements in the window. This method then attaches to first_label an agent called mouse_enter (which is the name I gave it) to a collection of pointer_enter_actions (you may have many actions you wish to perform when the mouse enters the label). Although mouse_enter is _my_ name for the agent, the agent itself is supplied by EiffelBuild and encapsulates the Microsoft Windows event associated with mouse pointer entry. Imagine, if you will, being able to name .Click or .MouseEnter in VFP anything you want. Eiffel separates the name of an event from the OS's implementation of the event.

I know this seems like RaiseEvent() and BindEvent(), and indeed agents in Eiffel are similar. But agents encapsulate the event-handling process. VFP does not. What I mean by that is that if you raise an event two or three levels deep in a container hierarchy with the expectation that a container higher up might bind to it, all of the contained objects have to be declared as PUBLIC. Make them PROTECTED or HIDDEN and the event processor can't see them. So, this forces you to expose elements of your class to consumer of your class that you may not wish exposed.

If the Eiffel code above seems stark, well, it is. Eiffel has only 26 keywords in its language. All of its functionality comes from class libraries, about 15 of which are included with EiffelStudio, encapsulating everything from GDI+ to database manipulation. There are _no_ free functions allowed. Every method _must_ be part of a class definition.

So why am I using VFP? First, my client insists, despite the fact that I told them that I haven't programmed in VFP since 1994. Didn't matter. They told me to learn quickly. Second, I love VFP anyways, warts and all. Besides, Eiffel is an extremely high standard in the world of OOP. Holding a data-centric language and IDE to that standard would be unfair. Even C++ and C# fall apart upon closer scrutiny. Smalltalk is Eiffel's only true competitor, but with weak typing and no support for multiple inheritance, it too is fraught with problems.

Eric
Précédent
Suivant
Répondre
Fil
Voir

Click here to load this message in the networking platform