[Xotcl] parameters to keep Class objects
Stefan Sobernig
stefan.sobernig at wu.ac.at
Fri Sep 15 12:07:58 CEST 2023
Hi Maksym!
> Basically I want something like *Factory Method* pattern.
This clarifies your request! Thanks!
Looking at your design snippet, I would have some suggestions for
improvement.
From what I see, your design is not really realising the advantages of
the FACTORY METHOD (e.g., adding new types of sessions *without* having
to touch the factory method and the switch in there), nor is it very
robust because of re-using the NX constructor "init" as the factory method.
o Robustness: Re-using "init" that way is not a good choice in the
context of NaviServer, because unless you are careful, NaviServer will
run "init" just once (when building the blueprint script). When shipping
the script to the interpreters of connection threads, init will not be
run again (-noinit is added). In addition, autonamed NX objects (those
created via calling "new") are also not exported into the blueprint
script. Hence, you experience the "${:storageObj} doesn't exist" issue
in the connection threads.
o FACTORY METHOD: The by-the-book design of a FM implementation creates
two lines of concepts: session factories and sessions. For both lines,
two class hierarchies are typically created, like:
namespace eval ::oodz {
nx::Class create Session {
:public method save {args} {;}
}
nx::Class create FileSession -superclasses Session
nx::Class create DBSession -superclasses Session
nx::Class create SessionFactory {
:public method createSession {} {
error "[:info class]: abstract method, use subclass!"
}
:create ::sessionFactory
}
nx::Class create FileSessionFactory -superclasses SessionFactory {
:public method createSession {} {
return [FileSession new]
}
}
nx::Class create DBSessionFactory -superclasses SessionFactory {
:public method createSession {} {
return [DBSession new]
}
}
namespace export Session DBSessionFactory DBSession
FileSessionFactory FileSession
}
This way, you could call:
namespace import ::oodz::*
set s [[DBSessionFactory new] createSession]
$s save
This is a lot of design boilerplate, I prefer the following (using NX/
XOTcl idioms incl. a metaclass):
namespace eval ::oodz {
nx::Class create SessionClass -superclasses ::nx::Class
SessionClass create Session {
:public method save {args} {;}
}
SessionClass create file -superclasses Session
SessionClass create db -superclasses Session
nx::Class create SessionFactory {
:public method createSession {-persist_type:class,type=SessionClass} {
return [$persist_type new]
}
:create sessionFactory
}
namespace export sessionFactory file db
}
Then:
namespace import -force ::oodz::*
set s [sessionFactory createSession -persist_type db]
$s save
Some remarks:
- "init" is not used!
- session-class names are used as first-class symbols of your factory
method (no need to maintain yet another mapping: "file" <->
"FileSession" or similar)
- You can easily add new session types, by creating new SessionClass
instances;
- Clearly, as always, there are alternatives (e.g., maintain a
dictionary of persist_types symbols and session classes).
HTH, Stefan
> happening right now is that I am initializing my Session class. It works
> fine but after some time I'm getting an error that ${:storageObj} doesnt
> exist.
> In your example I need to know my type of the class before. Sorry, maybe
> I understood wrong. If you have a simple example of illustrating factory
> method I would be grateful.
> Thank you
>
> On Tue, Sep 12, 2023 at 7:02 AM Stefan Sobernig
> <stefan.sobernig at wu.ac.at <mailto:stefan.sobernig at wu.ac.at>> wrote:
>
> Hi Maksym!
>
> I would recommend using a "property", watch:
>
> package req nx
>
> nx::Class create a {
> :public method hmmm {} {
> return "Hmmmm!!!"
> }
> }
> nx::Class create b {
> :property -accessor public aObj:object,type=::a
>
> :public method saysmth {} {
> puts "Hello!? [${:aObj} hmmm]"
> }
> }
>
>
> # in init.tcl / created once
> ::b create bobj
>
> # somewhere else (later):
>
> ::bobj aObj set [::a new]
> ::bobj saysmth
>
> What do you think?
>
> HTH, Stefan
>
>
> > Hello, can I use parameters to keep Class objects? Like this:
> >
> > package require nx
> >>
> >> nx::Class create a {
> >> :public method hmmm {} {
> >> return "Hmmmm!!!"
> >> }
> >> }
> >>
> >> nx::Class create b {
> >> :method init {} {
> >> set :aObj [a new]
> >> }
> >>
> >> :public method saysmth {} {
> >> puts "Hello!? [${:aObj} hmmm]"
> >> }
> >> }
> >>
> >> ::b create bobj
> >> ::bobj saysmth
> >>
> > Is it possible that it will not be set if I create my "bobj" from
> init.tcl
> > in Naviserver at startup?
> >
> > Thank you in advance
> > _______________________________________________
> > Xotcl mailing list
> > Xotcl at alice.wu.ac.at <mailto:Xotcl at alice.wu.ac.at>
> > http://alice.wu.ac.at/mailman/listinfo/xotcl
> <http://alice.wu.ac.at/mailman/listinfo/xotcl>
>
> _______________________________________________
> Xotcl mailing list
> Xotcl at alice.wu.ac.at <mailto:Xotcl at alice.wu.ac.at>
> http://alice.wu.ac.at/mailman/listinfo/xotcl
> <http://alice.wu.ac.at/mailman/listinfo/xotcl>
>
More information about the Xotcl
mailing list