Multi-Module Alternative to the Factory Pattern?

Discussion in 'Ruby' started by Trans, Sep 28, 2006.

  1. Trans

    Trans Guest

    I've been using a factory pattern for a set of packaging classes
    --classes that generate different package formats (eg. Debian, RPM,
    etc.), but it's not quite the right fit b/c it leads to repetition of
    the staging step. Yuk! So I think a better fit is to have one class
    (Packager) that calls on external modules (or classes) for each
    different format. But, unfortuately there are quite a few attributes
    needed by each from the Packager, and it's just doesn't seem right to
    pass that many variables. So it seems like it would be better to just
    include the needed module into the Packager class as needed. But here
    again I can't un-include a format module once done with it in order to
    use another format. So I'm right back to using a factory pattern.

    Then I had this idea. and I'm wondering what others think of it.

    First we need this little extension from Facets:

    class Object

    # Like super but skips to a specific ancestor module or class.
    #
    # class A
    # def x ; 1 ; end
    # end
    #
    # class B < A
    # def x ; 2 ; end
    # end
    #
    # class C < B
    # def x ; superior(A) ; end
    # end
    #
    # C.new.x #=> 1
    #
    def superior(klass=self.class.superclass, *args, &blk)
    unless self.class.ancestors.include?(klass)
    raise ArgumentError
    end
    called = /\`([^\']+)\'/.match(caller(1).first)[1].to_sym
    klass.instance_method(called).bind(self).call(*args,&blk)
    end

    end

    Then:

    module Debian
    def pack ; "Debian package"; end
    end

    module RPM
    def pack ; "RPM package"; end
    end

    class Packager
    include Debian, RPM

    def pack( type )
    superior(type)
    end
    end

    pkgr = Packager.new
    pkgr.pack(Debian) #=> "Debian package"
    pkgr.pack(RPM) #=> "RPM package"

    What do you think?

    Thanks,
    T.
    Trans, Sep 28, 2006
    #1
    1. Advertising

  2. Trans

    Pit Capitain Guest

    Trans schrieb:
    > I've been using a factory pattern for a set of packaging classes
    > --classes that generate different package formats (eg. Debian, RPM,
    > etc.), but it's not quite the right fit b/c it leads to repetition of
    > the staging step. Yuk! So I think a better fit is to have one class
    > (Packager) that calls on external modules (or classes) for each
    > different format. But, unfortuately there are quite a few attributes
    > needed by each from the Packager, and it's just doesn't seem right to
    > pass that many variables. (...)


    Tom, couldn't you pass the packager itself to the external modules and
    let them query the attributes they need?

    Regards,
    Pit
    Pit Capitain, Sep 28, 2006
    #2
    1. Advertising

  3. Trans

    Trans Guest

    Hi Pit--

    Pit Capitain wrote:
    > Tom, couldn't you pass the packager itself to the external modules and
    > let them query the attributes they need?


    Yes. That would work too. And that might be the best way to do it.
    Though it still means writing code to do the attribute transfer, but
    that can be automated fairly easily.

    I'm still curious about this "multi-module" idea in general though.
    Seems like it could be an alternative to code injection too.

    T.
    Trans, Sep 28, 2006
    #3
  4. Trans

    Guest

    On Thu, 28 Sep 2006, Trans wrote:

    > Hi Pit--
    >
    > Pit Capitain wrote:
    >> Tom, couldn't you pass the packager itself to the external modules and
    >> let them query the attributes they need?

    >
    > Yes. That would work too. And that might be the best way to do it.
    > Though it still means writing code to do the attribute transfer, but
    > that can be automated fairly easily.
    >
    > I'm still curious about this "multi-module" idea in general though.
    > Seems like it could be an alternative to code injection too.
    >
    > T.


    why not:

    harp:~ > cat a.rb
    module DEB
    A, B, C = %w( D E B )
    def self.pack_step_one() p A end
    def self.pack_step_two() p B end
    def self.pack_step_three() p C end
    def self.pack_step_four(arg) p arg end
    end

    module RPM
    A, B, C = %w( R P M )
    def self.pack_step_one() p A end
    def self.pack_step_two() p B end
    def self.pack_step_three() p C end
    def self.pack_step_four(arg) p arg end
    end

    class Packager
    def initialize type
    @type = type
    end
    def pack arg
    @type.instance_eval{
    pack_step_one
    pack_step_two
    pack_step_three
    pack_step_four arg
    }
    end
    end

    packager = Packager.new DEB
    packager.pack 42


    harp:~ > ruby a.rb
    "D"
    "E"
    "B"
    42

    ??

    btw. for these kinds of setups: modules with state (singletons) i've been
    using prototypes lately:

    harp:~ > cat a.rb
    require 'prototype'

    DEB = prototype{
    @a, @b, @c = %w( D E B )
    def pack_step_one() p @a end
    def pack_step_two() p @b end
    def pack_step_three() p @c end
    def pack_step_four(arg) p arg end
    }

    RPM = prototype{
    @a, @b, @c = %w( D E B )
    def pack_step_one() p @a end
    def pack_step_two() p @b end
    def pack_step_three() p @c end
    def pack_step_four(arg) p arg end
    }


    class Packager
    attr 'type'
    def initialize type
    @type = type
    end
    def pack arg
    @type.instance_eval{
    pack_step_one
    pack_step_two
    pack_step_three
    pack_step_four arg
    }
    end
    end

    packager = Packager.new DEB
    packager.pack 42

    harp:~ > ruby -r rubygems a.rb
    "D"
    "E"
    "B"
    42


    i guess i'm failing to see what multi-module inclusion givs you that delegation
    plus argument passing (into the delegate module not the other way around)
    doesn't?

    regards.


    -a
    --
    in order to be effective truth must penetrate like an arrow - and that is
    likely to hurt. -- wei wu wei
    , Sep 28, 2006
    #4
  5. Trans

    Trans Guest

    wrote:
    > why not:
    > [snip]


    Only becuase there are a lot of arguments to pass.

    > btw. for these kinds of setups: modules with state (singletons) i've been
    > using prototypes lately:


    Right on. I do like the prototype stuff. Just don't have the time to
    invest init at them moment though.

    [snip cool example use of prototype]

    > i guess i'm failing to see what multi-module inclusion givs you that delegation
    > plus argument passing (into the delegate module not the other way around)
    > doesn't?


    The advantage is access to the internal state --no passing of
    attributes required. Esspecailly true when you have alot of
    attributes/arguments involved. Simple example:

    require 'facet/kernel/as'

    module DEB
    A, B, C = %w( D E B )
    def pack_step_one() p A+a end
    def pack_step_two() p B+b end
    def pack_step_three() p C+c end
    end

    module RPM
    A, B, C = %w( R P M )
    def pack_step_one() p A+a+b+c end
    def pack_step_two() p B+b+c+a end
    def pack_step_three() p C+c+a+b end
    end

    class Packager
    include DEB, RPM
    attr :a,:b,:c
    def initialize
    @a,@b,@c = %w{ 1 2 3 }
    end
    def pack type
    as(type).pack_step_one
    as(type).pack_step_two
    as(type).pack_step_three
    end
    end

    packager = Packager.new
    packager.pack DEB, 42

    harp:~ > ruby a.rb
    "D123"
    "E231"
    "B312"
    42

    Note #as works like #superior from my last example but uses magic-dot
    notation to allow any method to be called. (It would be nice if it took
    a block but I'll have to work on that).

    T.
    Trans, Sep 28, 2006
    #5
  6. Trans

    Guest

    On Fri, 29 Sep 2006, Trans wrote:

    > Only becuase there are a lot of arguments to pass.


    hash? array?

    >> i guess i'm failing to see what multi-module inclusion givs you that
    >> delegation plus argument passing (into the delegate module not the other
    >> way around) doesn't?

    >
    > The advantage is access to the internal state --no passing of attributes
    > required. Esspecailly true when you have alot of attributes/arguments
    > involved. Simple example:
    >
    > require 'facet/kernel/as'
    >
    > module DEB
    > A, B, C = %w( D E B )
    > def pack_step_one() p A+a end
    > def pack_step_two() p B+b end
    > def pack_step_three() p C+c end
    > end
    >
    > module RPM
    > A, B, C = %w( R P M )
    > def pack_step_one() p A+a+b+c end
    > def pack_step_two() p B+b+c+a end
    > def pack_step_three() p C+c+a+b end
    > end
    >
    > class Packager
    > include DEB, RPM
    > attr :a,:b,:c
    > def initialize
    > @a,@b,@c = %w{ 1 2 3 }
    > end
    > def pack type
    > as(type).pack_step_one
    > as(type).pack_step_two
    > as(type).pack_step_three
    > end
    > end
    >
    > packager = Packager.new
    > packager.pack DEB, 42
    >
    > harp:~ > ruby a.rb
    > "D123"
    > "E231"
    > "B312"
    > 42
    >
    > Note #as works like #superior from my last example but uses magic-dot
    > notation to allow any method to be called. (It would be nice if it took a
    > block but I'll have to work on that).



    hmm. how bout this:

    harp:~ > cat a.rb
    class Object
    def including m, &b
    (class << (d=dup); self; end).module_eval{ include m }
    d.instance_eval &b
    end
    end

    module DEB
    A, B, C = %w( D E B )
    def pack_step_one() p A+a end
    def pack_step_two() p B+b end
    def pack_step_three() p C+c end
    end

    module RPM
    A, B, C = %w( R P M )
    def pack_step_one() p A+a+b+c end
    def pack_step_two() p B+b+c+a end
    def pack_step_three() p C+c+a+b end
    end

    class Packager
    [:a,:b,:c].each{|a| attr a}

    def initialize
    @a,@b,@c = %w{ 1 2 3 }
    end

    def pack type, *a
    including(type){
    pack_step_one
    pack_step_two
    pack_step_three
    }
    end
    end

    packager = Packager.new
    packager.pack DEB, 42


    harp:~ > ruby a.rb
    "D1"
    "E2"
    "B3"

    sure the performance will suck though ;-(

    fun stuff...

    i like your 'as' method.

    -a
    --
    in order to be effective truth must penetrate like an arrow - and that is
    likely to hurt. -- wei wu wei
    , Sep 28, 2006
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ashish
    Replies:
    1
    Views:
    430
    Karl Seguin
    Jan 20, 2005
  2. =?Utf-8?B?bWF4?=

    Design Pattern - Abstract Factory

    =?Utf-8?B?bWF4?=, Oct 18, 2005, in forum: ASP .Net
    Replies:
    2
    Views:
    650
    tdavisjr
    Oct 18, 2005
  3. Medi Montaseri
    Replies:
    17
    Views:
    851
    Medi Montaseri
    Sep 3, 2003
  4. sunny
    Replies:
    1
    Views:
    459
    Salt_Peter
    Dec 7, 2006
  5. C#
    Replies:
    4
    Views:
    395
Loading...

Share This Page