Is this a kind of design patterns?

S

Sam Kong

Hi!

Sometimes a class provides object instantiation methods other than new.
See an example.

class Color
def initialize r, g, b
@r = r
@g = g
@b = b
end

def to_s
"R: #{@r}, G: #{@g}, B: #{@b}"
end

class << self
def red
new 255, 0, 0
end

def blue
new 0, 0, 255
end

def green
new 0, 255, 0
end
end
end

puts Color.new(100, 120, 140)
puts Color.red
puts Color.blue


Is this one of design patterns, or just a simple idiom?
It's similar to a factory method pattern but it's not according to the
definition.
Is there any name for it?

TIA.

Sam
 
K

killy-kun

Sam said:
Hi!

Sometimes a class provides object instantiation methods other than new.
See an example.

class Color
def initialize r, g, b
@r = r
@g = g
@b = b
end

def to_s
"R: #{@r}, G: #{@g}, B: #{@b}"
end

class << self
def red
new 255, 0, 0
end

def blue
new 0, 0, 255
end

def green
new 0, 255, 0
end
end
end

puts Color.new(100, 120, 140)
puts Color.red
puts Color.blue


Is this one of design patterns, or just a simple idiom?
It's similar to a factory method pattern but it's not according to the
definition.
Is there any name for it?

TIA.

Sam

isn't that the facory design pattern ?
 
D

Daniel Baird

------=_Part_2518_33203729.1143020081342
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

The truth is, as a ganeral rule the original G4 design patterns were kinda
statically-typed-language-centric, so it wouldn't surprise me if there was
some small details in Ruby versions of the patterns that didn't quite fit
the "classic" description.

In this case though, it does look a lot like the Factory pattern, apart fro=
m
new still being available. I think if Color.new was re-declared as private=
,
that would make it a textbook case of the Factory pattern.

IANA(language)L though..

;Daniel

isn't that the facory design pattern ?


--
Daniel Baird
http://danielbaird.com (TiddlyW;nks! :: Whiteboard Koala :: Blog :: Things
That Suck)
[[My webhost uptime is ~ 92%.. if no answer pls call again later!]]

------=_Part_2518_33203729.1143020081342--
 
R

Robert Klemme

Sam said:
Hi!

Sometimes a class provides object instantiation methods other than new.
See an example.

class Color
def initialize r, g, b
@r = r
@g = g
@b = b
end

def to_s
"R: #{@r}, G: #{@g}, B: #{@b}"
end

class << self
def red
new 255, 0, 0
end

def blue
new 0, 0, 255
end

def green
new 0, 255, 0
end
end
end

puts Color.new(100, 120, 140)
puts Color.red
puts Color.blue


Is this one of design patterns, or just a simple idiom?
It's similar to a factory method pattern but it's not according to the
definition.
Is there any name for it?

Since you invoke a class's method "new" like any other method of any
other object (no special syntax) you can say with some justification
that all classes are basically factories.

IMHO your example is not optimal because it wastes resources. Since
Color is immutable anyway constants seem a better choice:

Color = Struct.new :r, :g, :b
class Color
def to_s
sprintf "R: 0x%02x, G: 0x%02x, B: 0x%02x", self.r, self.g, self.b
end

RED = new 0xFF, 0x00, 0x00
BLUE = new 0x00, 0x00, 0xFF
GREEN = new 0x00, 0xFF, 0x00
end

Kind regards

robert
 
W

Wilson Bilkovich

Hi!

Sometimes a class provides object instantiation methods other than new.
See an example.

class Color
def initialize r, g, b
@r =3D r
@g =3D g
@b =3D b
end

def to_s
"R: #{@r}, G: #{@g}, B: #{@b}"
end

class << self
def red
new 255, 0, 0
end

def blue
new 0, 0, 255
end

def green
new 0, 255, 0
end
end
end

puts Color.new(100, 120, 140)
puts Color.red
puts Color.blue


Is this one of design patterns, or just a simple idiom?
It's similar to a factory method pattern but it's not according to the
definition.
Is there any name for it?

That's the "Factory Method" pattern. It's handy when you want
SomeClass.new to return an instance of SomeOtherClass, or just when
you want things to be easier to read.

One of my favorite examples (I think this is a Martin Fowler trick) is:
some_date =3D december(10,2006)
 
S

Sam Kong

Wilson said:
That's the "Factory Method" pattern. It's handy when you want
SomeClass.new to return an instance of SomeOtherClass, or just when
you want things to be easier to read.

One of my favorite examples (I think this is a Martin Fowler trick) is:
some_date = december(10,2006)

At first I thought so.
But the definition of "Factory Method Pattern" bothered me.
The definition of "Factory Method Pattern" is:

"Define an interface for creating an object, but let subclasses decide
which class to instantiate. Factory Method lets a class defer
instantiation to subclasses. "

However, in my Color example, there's no subclassing involved.
So the class itself is a factory as well as the product that the
factory makes.
Do you think that we can still call it "Factory Method Pattern"?

Sam
 
S

Sam Kong

Robert said:
Since you invoke a class's method "new" like any other method of any
other object (no special syntax) you can say with some justification
that all classes are basically factories.

IMHO your example is not optimal because it wastes resources. Since
Color is immutable anyway constants seem a better choice:

Color = Struct.new :r, :g, :b
class Color
def to_s
sprintf "R: 0x%02x, G: 0x%02x, B: 0x%02x", self.r, self.g, self.b
end

RED = new 0xFF, 0x00, 0x00
BLUE = new 0x00, 0x00, 0xFF
GREEN = new 0x00, 0xFF, 0x00
end

This looks tricky and wonderful.
I just tried to make a simple example which was not intended to be
ooptimal.
I will apply your way when I need to make a real code.:)
Thank you.

Sam
 
J

Jim Weirich

Robert said:
Since you invoke a class's method "new" like any other method of any
other object (no special syntax) you can say with some justification
that all classes are basically factories.

IMHO your example is not optimal because it wastes resources. Since
Color is immutable anyway constants seem a better choice:

Color = Struct.new :r, :g, :b
class Color
def to_s
sprintf "R: 0x%02x, G: 0x%02x, B: 0x%02x", self.r, self.g, self.b
end

RED = new 0xFF, 0x00, 0x00
BLUE = new 0x00, 0x00, 0xFF
GREEN = new 0x00, 0xFF, 0x00
end

I was thinking along the same lines, but I do like the method interface
(e.g. Color.red over Color::RED). My suggestion would have been
something like:

class Color
...
class << self
def red
@red ||= new 255, 0, 0
end
...
end
end
 
J

Jim Weirich

Wilson said:
Is this one of design patterns, or just a simple idiom? [...]

That's the "Factory Method" pattern. It's handy when you want
SomeClass.new to return an instance of SomeOtherClass, or just when
you want things to be easier to read.

Hmmm ... It's not the GOF Factory Method pattern. It doesn't even solve
the same problem that the Factory Method pattern is designed to address.

But it is a useful technique ... pattern or not.
 
M

Mark Volkmann

Robert Klemme wrote:

class Color
...
class << self
def red
@red ||=3D new 255, 0, 0
end
...
end
end

Is there any difference between the above code and this?

class Color
...
def self.red
@red ||=3D new 255, 0, 0
end
...
end
 
J

Joel VanderWerf

Jim said:
I was thinking along the same lines, but I do like the method interface
(e.g. Color.red over Color::RED). My suggestion would have been
something like:

class Color
...
class << self
def red
@red ||= new 255, 0, 0
end
...
end
end

And this is tantamount to dependency injection. For example, with my
mindi framework (findable on RAA), there is the examples/color-namespace.rb:

require 'mindi'

class PictureApp
include MinDI::InjectableContainer

class Picture
attr_reader :eek:pts
def initialize(opts)
@opts = opts
end
end

class Color < Struct.new:)r, :g, :b)
def +(color)
Color.new(r + color.r, g + color.g, b + color.b)
end
end

class ColorNamespace
include MinDI::InjectableContainer

red { Color.new(1,0,0) }
green { Color.new(0,1,0) }
yellow { red + green }
end

colors { ColorNamespace.new }
picture { Picture.new:)background => colors.yellow) }
end

pic_app = PictureApp.new
pic = pic_app.picture
raise unless pic.opts[:background] == pic_app.colors.yellow
 
R

Robert Klemme

Jim said:
I was thinking along the same lines, but I do like the method interface
(e.g. Color.red over Color::RED). My suggestion would have been
something like:

class Color
...
class << self
def red
@red ||= new 255, 0, 0
end
...
end
end

IMHO this is not thread safe. If you need the method interface, you
could do something like

class Color
def self.method_missing(s,*a,&b)
if a.empty? && b.nil?
const_get s.to_s.upcase
else
super
end
end
end

:)

robert
 
R

Robert Dober

------=_Part_1914_14013178.1143106142635
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

let us wrap
const_get

begin
const_get(...)
rescue NameError
super(...)
end
in order to get NoMethodError instead of a NameError

Cheers
Robert
IMHO this is not thread safe. If you need the method interface, you
could do something like

class Color
def self.method_missing(s,*a,&b)
if a.empty? && b.nil?
const_get s.to_s.upcase
else
super
end
end
end

:)

robert


--
Deux choses sont infinies : l'univers et la b=EAtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

------=_Part_1914_14013178.1143106142635--
 
J

Jim Weirich

Robert said:
IMHO this is not thread safe. If you need the method interface, you
could do something like [...]
:)

I did catch the smiley. :)

Given that the original returned a new object on every invocation, a
race condition that might generate an extra light weight object or two
at initialization seems to be a low risk.

However, if I were really concerned about the race condition, I think I
would go the metaprogramming route rather then the dynamic lookup route.
Something more like this:

class Color
...
class << self
private
def define(name, color)
class_eval "#{name.to_s.upcase} = color"
class_eval "def Color.#{name}; #{name.to_s.upcase}; end"
end
end

define :red, Color.new(255, 0, 0)
...
end

;)
 
R

Robert Dober

------=_Part_4146_15713315.1143120660555
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Is there any difference between the above code and this?

class Color
...
def self.red
@red ||=3D new 255, 0, 0
end
...
end


No, not at my knowledge

--
R. Mark Volkmann
Object Computing, Inc.


--
Deux choses sont infinies : l'univers et la b=EAtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

------=_Part_4146_15713315.1143120660555--
 
R

Robert Klemme

Jim said:
Robert said:
IMHO this is not thread safe. If you need the method interface, you
could do something like [...]
:)

I did catch the smiley. :)
:)

Given that the original returned a new object on every invocation, a
race condition that might generate an extra light weight object or two
at initialization seems to be a low risk.

However, if I were really concerned about the race condition, I think I
would go the metaprogramming route rather then the dynamic lookup route.
Something more like this:

class Color
...
class << self
private
def define(name, color)
class_eval "#{name.to_s.upcase} = color"
class_eval "def Color.#{name}; #{name.to_s.upcase}; end"
end
end

define :red, Color.new(255, 0, 0)
...
end

;)

:)

Since we're in Color anyway, you can simplify the definition that by

class Color
# ...
class << self
private
def define(name, *args)
cname = name.to_s.upcase
col = const_set( cname, new(*args))
class_eval "def self.#{name}; #{cname}; end"
end
end

define :red, 255, 0, 0
# ...
end

:)

Kind regards

robert
 
J

Jim Weirich

Robert said:
Since we're in Color anyway, you can simplify the definition that by

I like that.

And I love the collective refactoring that goes on in this list!
 
S

Stephen Bannasch

I have a bunch of template documents which I need to manipulate in
very simple ways. I'd like to be able to insert Ruby variables into
the template. Here is a very short example:

file fruit_template.txt: This is a fruit: #{fruit}.

fruit = "apple"
f = IO.read("fruit_template.txt")

Then somehow I'd like to end up with this string:
"This is a fruit: apple."

This works fine of course if I construct the string in Ruby:
s = "This is a fruit: #{fruit}."
=> "This is a fruit: apple."

Thanks for any advice.
 
J

James Edward Gray II

I have a bunch of template documents which I need to manipulate in
very simple ways. I'd like to be able to insert Ruby variables into
the template. Here is a very short example:

file fruit_template.txt: This is a fruit: #{fruit}.

fruit = "apple"
f = IO.read("fruit_template.txt")

Then somehow I'd like to end up with this string:
"This is a fruit: apple."

The easy answer to your question is to use eval():
=> "This is a fruit: apple."

The right answer is to use a template library, like the standard ERB:
=> "This is a fruit: apple."

Hope that helps.

James Edward Gray II
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top