From: ·············@my-deja.com
Subject: State Pattern in CLOS
Date: 
Message-ID: <94fh01$rh$1@nnrp1.deja.com>
What's the usual way to implement the state pattern (from "Design
Patterns" book) in CLOS? O:-)

TIA


Sent via Deja.com
http://www.deja.com/
From: Pierre R. Mai
Subject: Re: State Pattern in CLOS
Date: 
Message-ID: <87ofx0o5jl.fsf@orion.bln.pmsf.de>
·············@my-deja.com writes:

> What's the usual way to implement the state pattern (from "Design
> Patterns" book) in CLOS? O:-)

To quote from the implementation section of said book (page 309):

<quote>
4. Using dynamic inheritance.  Changing the behaviour for a particular
   request could be accomplished by changing the object's class at
   run-time, but this is not possible in most object-oriented
   programming languages.  Exceptions include Self [US87] and other
   delegation-based languages that provide such a mechanism and hence
   support the State pattern directly.
</quote>

CLOS is not a delegation-based language, but it does support
changing the class of an object directly, via change-class.  Here a
short excerpt from MaiSQL, where all open database connections are
sub-classes of the class database, which get turned into
closed-database objects upon disconnection:

(defclass database ()
  ((name :initarg :name :reader database-name))
  (:documentation
   "This class is the supertype of all databases handled by MaiSQL."))

(defclass closed-database ()
  ((name :initarg :name :reader database-name))
  (:documentation
   "This class represents all databases after they are closed via
`disconnect'."))

(defun query (query-expression &key (database *default-database*))
  "Execute the SQL query expression query-expression on the given database.
Returns a list of lists of values of the result of that expression."
  (database-query query-expression database))

(defgeneric database-query (query-expression database)
  (:method (query-expression (database closed-database))
           (declare (ignore query-expression))
           (signal-closed-database-error database))
  (:documentation "Internal generic implementation of query."))

(defun disconnect (&key (database *default-database*))
  "Closes the connection to database. Resets *default-database* if that
database was disconnected and only one other connection exists."
  (when (database-disconnect database)
    (setq *connected-databases* (delete database *connected-databases*))
    (when (eq database *default-database*)
      (setq *default-database* (car *connected-databases*)))
    (change-class database 'closed-database)
    t))

(defgeneric database-disconnect (database)
  (:method ((database closed-database))
           (signal-closed-database-error database))
  (:documentation "Internal generic implementation of disconnect."))

Regs, Pierre.

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein