A question on the builder pattern

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

A question on the builder pattern

Andreas.Raab
Hi -

Over the weekend I realized an interesting difference in the utilization
of the builder pattern. It is related with how to create and interact
with new entities created by the builder, and goes like this:

Form a: In this form (which is utilized by ToolBuilder) a request for a
new item creates an instance of the item which is then populated with
the desired set of attributes, for example

        ^(builder pluggableListSpec new)
                model: tool;
                list: listSymbol;
                getIndex: selectionSymbol;
                setIndex: selectionSymbol asMutator;
                frame: currentFrame;
                yourself

The expression "builder pluggableListSpec new" (or some variant like
"builder newObject") creates an instance of the item, returns it, and
then we set various properties on it.

Form b: In this form (which is utilized for example by Metacello or by
Pharo's Settings package) the builder generally returns *self* (it may
return some other builder object but from what I've seen it never
returns the actual entity created) from the request to create a new
entity, and effectively "proxies" the follow-on requests, for example:

        (aBuilder pickOne: #displayDepth)
                label: 'Display depth' translated;
                parent: #appearance;
                target: #Display;
                getSelector: #depth;
                setSelector: #newDepth:;
                domainValues: self depthChoices;
                notInStyle.

The expression "aBuilder pickOne: #displayDepth" returns another builder
which then assembles the various attributes. The more canonical use of
this form seems to be utilized via an implicit block scope in the
construction request, like here:

        spec project: 'OB-Standard' with: [
                spec
                        className: 'ConfigurationOfOmniBrowser';
                        loads: #('OB-Standard' );
                        file: 'ConfigurationOfOmniBrowser';
                        repository: 'http://www.squeaksource.com/MetacelloRepository' ].

In this form the 'project' is created by the 'spec' (constructor)
internally and then populated via the follow-on messages (#className:,
#loads:, #file:, #repository) sent to the 'spec' and from there
forwarded internally to the project under construction.

[Btw, it's not entirely clear to me whether these two forms really
represent the same idea or if we need to split them into "form b" using
nested builders and cascades and "form c" operating on scoped blocks. In
any case...]

What I'm curious about is this: Which advantage does "form b" have over
"form a"? Why would one choose it? Is it merely for convenience or are
there other (practical or style) advantages?

Cheers,
   - Andreas

_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: A question on the builder pattern

Dale
Andreas,

I think the advantage of form B comes when you end up nesting the build instructions:

spec for: #common do: [
  spec blessing: #baseline.
  spec description: 'Descriptive comment'.
  spec
    project: 'UI Support' with: [
      spec
        className: 'UIConfig';
        loads: #('UI-Core' );  
        repository: 'http://www.example.com/r' ].
  spec
    package: 'Example-AddOn' with: [                                                
      spec
        requires: #('Example-Core' );
        includes: #('Example-UI' );
        repositories: [
          spec
            repository: 'http://www.example.com/yar'; 
            repository: 'http://www.example.com/yas']]].

You can't construct the above as a cascade, so you end up having to create temp variables, etc. Like the following for form A:

| common pkg |
common := (spec for: #common)
  blessing: #baseline;
  description: 'Descriptive comment'.
(common
  project: 'UI Support')
    className: 'UIConfig';
    loads: #('UI-Core' );  
    repository: 'http://www.example.com/r'.
pkg := common
  package: 'Example-AddOn'.
pkg
  requires: #('Example-Core' );
  includes: #('Example-UI' ).
pkg repositories
  repository: 'http://www.example.com/yar';
  repository: 'http://www.example.com/yas'.

When I scan form B (with nested blocks) it is very clear that the repositories are associated with the package 'Example-AddOn'. If form A, it's not as obvious.

Dale
   
----- "Andreas Raab" <[hidden email]> wrote:

| Hi -
|
| Over the weekend I realized an interesting difference in the
| utilization
| of the builder pattern. It is related with how to create and interact
|
| with new entities created by the builder, and goes like this:
|
| Form a: In this form (which is utilized by ToolBuilder) a request for
| a
| new item creates an instance of the item which is then populated with
|
| the desired set of attributes, for example
|
| ^(builder pluggableListSpec new)
| model: tool;
| list: listSymbol;
| getIndex: selectionSymbol;
| setIndex: selectionSymbol asMutator;
| frame: currentFrame;
| yourself
|
| The expression "builder pluggableListSpec new" (or some variant like
| "builder newObject") creates an instance of the item, returns it, and
|
| then we set various properties on it.
|
| Form b: In this form (which is utilized for example by Metacello or by
|
| Pharo's Settings package) the builder generally returns *self* (it may
|
| return some other builder object but from what I've seen it never
| returns the actual entity created) from the request to create a new
| entity, and effectively "proxies" the follow-on requests, for
| example:
|
| (aBuilder pickOne: #displayDepth)
| label: 'Display depth' translated;
| parent: #appearance;
| target: #Display;
| getSelector: #depth;
| setSelector: #newDepth:;
| domainValues: self depthChoices;
| notInStyle.
|
| The expression "aBuilder pickOne: #displayDepth" returns another
| builder
| which then assembles the various attributes. The more canonical use of
|
| this form seems to be utilized via an implicit block scope in the
| construction request, like here:
|
| spec project: 'OB-Standard' with: [
| spec
| className: 'ConfigurationOfOmniBrowser';
| loads: #('OB-Standard' );
| file: 'ConfigurationOfOmniBrowser';
| repository: 'http://www.squeaksource.com/MetacelloRepository' ].
|
| In this form the 'project' is created by the 'spec' (constructor)
| internally and then populated via the follow-on messages (#className:,
|
| #loads:, #file:, #repository) sent to the 'spec' and from there
| forwarded internally to the project under construction.
|
| [Btw, it's not entirely clear to me whether these two forms really
| represent the same idea or if we need to split them into "form b"
| using
| nested builders and cascades and "form c" operating on scoped blocks.
| In
| any case...]
|
| What I'm curious about is this: Which advantage does "form b" have
| over
| "form a"? Why would one choose it? Is it merely for convenience or are
|
| there other (practical or style) advantages?
|
| Cheers,
|    - Andreas
|
| _______________________________________________
| Pharo-project mailing list
| [hidden email]
| http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project

_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] A question on the builder pattern

Igor Stasenko
In reply to this post by Andreas.Raab
On 4 May 2010 06:05, Andreas Raab <[hidden email]> wrote:

> Hi -
>
> Over the weekend I realized an interesting difference in the utilization of
> the builder pattern. It is related with how to create and interact with new
> entities created by the builder, and goes like this:
>
> Form a: In this form (which is utilized by ToolBuilder) a request for a new
> item creates an instance of the item which is then populated with the
> desired set of attributes, for example
>
>        ^(builder pluggableListSpec new)
>                model: tool;
>                list: listSymbol;
>                getIndex: selectionSymbol;
>                setIndex: selectionSymbol asMutator;
>                frame: currentFrame;
>                yourself
>
> The expression "builder pluggableListSpec new" (or some variant like
> "builder newObject") creates an instance of the item, returns it, and then
> we set various properties on it.
>
> Form b: In this form (which is utilized for example by Metacello or by
> Pharo's Settings package) the builder generally returns *self* (it may
> return some other builder object but from what I've seen it never returns
> the actual entity created) from the request to create a new entity, and
> effectively "proxies" the follow-on requests, for example:
>
>        (aBuilder pickOne: #displayDepth)
>                label: 'Display depth' translated;
>                parent: #appearance;
>                target: #Display;
>                getSelector: #depth;
>                setSelector: #newDepth:;
>                domainValues: self depthChoices;
>                notInStyle.
>
> The expression "aBuilder pickOne: #displayDepth" returns another builder
> which then assembles the various attributes. The more canonical use of this
> form seems to be utilized via an implicit block scope in the construction
> request, like here:
>
>        spec project: 'OB-Standard' with: [
>                spec
>                        className: 'ConfigurationOfOmniBrowser';
>                        loads: #('OB-Standard' );
>                        file: 'ConfigurationOfOmniBrowser';
>                        repository:
> 'http://www.squeaksource.com/MetacelloRepository' ].
>
> In this form the 'project' is created by the 'spec' (constructor) internally
> and then populated via the follow-on messages (#className:, #loads:, #file:,
> #repository) sent to the 'spec' and from there forwarded internally to the
> project under construction.
>
> [Btw, it's not entirely clear to me whether these two forms really represent
> the same idea or if we need to split them into "form b" using nested
> builders and cascades and "form c" operating on scoped blocks. In any
> case...]
>

> What I'm curious about is this: Which advantage does "form b" have over
> "form a"? Why would one choose it? Is it merely for convenience or are there
> other (practical or style) advantages?
>

The b and c , essentially is a form of command pattern.
And there's more practical advantage, because style is not really
important, and can be changed :)

I am using a command pattern in SMorphic , which going to be the
replacement of ToolBuilder in some distant future :)
http://www.squeaksource.com/SMorphic

There is a class, SMorphStyle which works as a command recorder, which
is then can be applied to arbitrary morph.
Its just replays all commands to this morph, and do, it doesn't needs
to even know anything about the nature or morph,
or use specs to keep data in fields. Its just sending a messages to it.

builder := SMorphStyle new.

builder
     allSubmorphs;
     className: #PluggableButton;
      borderWidth: 10.

Here , the  #allSubmorphs ,  and #className: is a special messages,
known by builder, which changing its selection,
and a #borderWidth: is an example of an arbitrary message, which
should be sent to selection.

So, as you may guess, when you doing:

builder applyTo: myWindow

it changing the border widths of all its buttons to 10 :)
which can be written manually as:

(morph allSubmorphs select: [:m | m class= PluggableButton ]) do: [:m
| m borderWidth: 10 ].


> Cheers,
>  - Andreas
>
>



--
Best regards,
Igor Stasenko AKA sig.

_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project