C++ is *not* the only OO language (was: Re: PHP objects and public/private methods)
Giorgos Keramidas
keramida at ceid.upatras.gr
Wed Sep 5 02:50:23 EEST 2007
On 2007-09-05 01:11, Giorgos Keramidas <keramida at ceid.upatras.gr> wrote:
> Ένα CLOS class δεν έχει μόνο ένα superclass:
Κι ένα ακόμα παράδειγμα με 'function call chaining', που δείχνει ότι το
CLOS δεν υστερεί σε κάτι από το C++ inheritance μοντέλο. Για την
ακρίβεια, αυτό είναι πιο κοντά στο μοντέλο της C++ επειδή το method name
που υλοποιείται από δύο _άσχετα_ μεταξύ τους superclasses έχει σε αυτή
την περίπτωση το _ίδιο_ όνομα.
Ορίζουμε πρώτα τα 3 γνωστά πλέον classes:
shape streamable
| |
+-------------+-------------+
|
rectangle
| CL-USER> (defclass shape ()
| ((shape-name :initarg :shape-name
| :initform "A generic shape")))
| #<STANDARD-CLASS SHAPE>
| CL-USER> (defclass streamable ()
| ((streamable-name :initarg :streamable-name
| :initform "A streamable object")))
| #<STANDARD-CLASS STREAMABLE>
| CL-USER> (defclass rectangle (shape streamable)
| ((shape-name :initform "A rectangular shape")
| (streamable-name :initform "A streamable rectangle")))
| #<STANDARD-CLASS RECTANGLE>
Ορίζοντας ένα generic function με base-class το T (το "μαγικό"
superclass όλων των CLOS classes):
| CL-USER> (defgeneric show (t))
| #<STANDARD-GENERIC-FUNCTION SHOW (0)>
Τώρα επειδή είμαστε λίγο "περίεργοι", ορίζουμε ΠΡΩΤΑ ένα instance της
class `rectangle', παρόλο που ακόμα δεν έχουμε υλοποιήσει βασικά κανένα
specialization της `show' method:
| CL-USER> (defparameter *keramida* (make-instance 'rectangle))
| *KERAMIDA*
Μπορούμε ύστερα να ορίσουμε διαφορετικά method specializations,
τόσο για το `shape' class όσο και για το `streamable' class:
| CL-USER> (defmethod show ((s shape))
| (when (slot-boundp s 'shape-name)
| (format t "~&~A" (slot-value s 'shape-name)))
| (when (next-method-p)
| (call-next-method)))
| #<STANDARD-METHOD SHOW (SHAPE) {61BD9C79}>
| CL-USER> (defmethod show ((s streamable))
| (when (slot-boundp s 'streamable-name)
| (format t "~&~A" (slot-value s 'streamable-name)))
| (when (next-method-p)
| (call-next-method)))
| #<STANDARD-METHOD SHOW (STREAMABLE) {61CB9161}>
Και τα νέα μας method specializations παίζουν αυτομάτως:
| CL-USER> (show *keramida*)
| A rectangular shape
| A streamable rectangle
| NIL
Και τώρα πάμε να "επεκτείνουμε" κάπως το generic `show' function όλων
των αντικειμένων που έχουν ήδη φτιαχτεί και όλων όσα θα φτιαχθούν
αργότερα, στο μέλλον!
| CL-USER> (defmethod show ((obj t))
| (format nil "~&A ~A object" (class-of obj)))
| STYLE-WARNING: redefining SHOW (#<BUILT-IN-CLASS T>) in DEFMETHOD
| #<STANDARD-METHOD SHOW (T) {61FD1D19}>
Και αμέσως το generic function `show' ξέρει ότι αφού κάνει όλα τα άλλα
πράγματα που ξέρει να κάνει, επιστρέφει και το string που ορίσαμε στο
method implementation του T super-superclass:
| CL-USER> (show *keramida*)
| A rectangular shape
| A streamable rectangle
| "A #<STANDARD-CLASS RECTANGLE> object"
| CL-USER>
το εντυπωσιακό εδώ είναι ότι αλλάξαμε σε _runtime_ την υλοποίηση μιας
superclass method, και φυσικά η Lisp χωρίς να ιδρώσει καν, συνέχισε
να κάνει αυτό που ξέρει ότι πρέπει να κάνει (αυτός ήταν και ο σκοπός
των `(when (next-method-p) (call-next-method))' calls στα σημεία που
μπήκαν άλλωστε).
Κι αυτή η νέα υλοποίηση της superclass method, προφανώς, ισχύει ακόμα
και για αντικείμενα που φτιάχνονται αργότερα:
| CL-USER> (defparameter *v13* (make-instance 'rectangle))
| *v13*
| CL-USER> (show *v13*)
| A rectangular shape
| A streamable rectangle
| "A #<STANDARD-CLASS RECTANGLE> object"
| CL-USER>
More information about the Linux-greek-users
mailing list