# State pattern?

**URL:** <https://www.ruby-forum.com/t/state-pattern/94626>\
**Category:** Ruby\
**Created:** [January 7, 2006, 2:01am UTC](https://www.ruby-forum.com/t/state-pattern/94626 "2006-01-07T02:01:48Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Michael\_SentropieS\_S](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/6de8d8/32.png) [@Michael\_SentropieS\_S](https://www.ruby-forum.com/u/Michael_SentropieS_S)\
**Post date:** [January 7, 2006, 2:01am UTC](https://www.ruby-forum.com/t/state-pattern/94626/1 "2006-01-07T02:01:48Z")

</div>

Hello,

I found this State-pattern example on [1], and was interested to  
find a way to make this more useable for standard classes (not just  
servers as in the example)

I’am not so skilled in OO coding and ruby, so iam interested what you  
all think.  
(and is it another implementation of the state pattern or iam on the  
wrong path?)

[1] [http://www.rubygarden.org/ruby?StatePattern](http://www.rubygarden.org/ruby?StatePattern)

## So long

Michael ‘entropie’ Trommer; [http://ackro.org](http://ackro.org)

ruby -e “0.upto((a=‘njduspAhnbjm/dpn’).size-1){|x| a[x]-=1}; p  
‘mailto:’+a”

---

<div class="post-metadata">

**Author:** ![Michael\_SentropieS\_S](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/6de8d8/32.png) [@Michael\_SentropieS\_S](https://www.ruby-forum.com/u/Michael_SentropieS_S)\
**Post date:** [January 7, 2006, 3:05pm UTC](https://www.ruby-forum.com/t/state-pattern/94626/2 "2006-01-07T15:05:19Z")

</div>

Michael ‘entropie’ Trommer [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Hello,
> 
> I found this State-pattern example on [1], and was interested to  
> find a way to make this more useable for standard classes (not just  
> servers as in the example)
> 
> I’am not so skilled in OO coding and ruby, so iam interested what you  
> all think. (and is it another implementation of the state pattern or  
> iam on the  
> wrong path?)

Hm, I think you probably did not get there completely. For example the  
toggle state metchod is typically implemented in the each state class  
(every  
state knows the state that follows him under certain conditions, like a  
finite state automata distributed across several classes). Also  
inheriting  
TrueClass and FalseClass is generally not a good idea (instances of  
FalseClass’s subclass won’t be treated as false).

Have a look at this

class StateTest  
BaseState = Struct.new :owner  
class StateError \< Exception; end

class StateOn \< BaseState  
attr\_accessor :target  
def connect(target) raise StateError, “already connected” end  
def disconnect()  
return StateOff.new(owner), true  
end  
def description() [self, “We’re connected to #{target}”] end  
end

class StateOff \< BaseState  
def connect(target)  
st = StateOn.new(owner)  
st.target=target  
return st, true  
end

```
def disconnect() raise StateError, "already disconnected" end
def description() [self, "We're disconnected"] end

```

end

def initialize  
@state = StateOff.new(self)  
end

def method\_missing(m,\*a,&b)  
@state, result = @state.send(m,\*a,&b)  
result  
end  
end

irb(main):036:0\> t = StateTest.new  
=\> #\<StateTest:0x101a6cc0 @state=#\<struct StateTest::StateOff  
owner=#\<StateTest:0x101a6cc0 …\>\>\>  
irb(main):037:0\> t.description  
=\> “We’re disconnected”  
irb(main):038:0\> t.connect “foo”  
=\> true  
irb(main):039:0\> t.description  
=\> “We’re connected to foo”  
irb(main):040:0\> t.disconnect  
=\> true  
irb(main):041:0\> t.description  
=\> “We’re disconnected”  
irb(main):042:0\> t.disconnect  
(irb):21:in `disconnect': already disconnected (StateTest::StateError) from (irb):32:in `method\_missing’  
from (irb):42:in `irb_binding' from /usr/lib/ruby/1.8/irb/workspace.rb:52:in `irb\_binding’  
from :0

Of course you could choose different ways to update the owner’s state so  
you  
don’t have to use two return values for all methods. For example

class StateTest  
BaseState = Struct.new :owner  
class BaseState  
private  
def next\_state(new\_state)  
owner.instance\_eval { @state = new\_state }  
end  
end

class StateOff \< BaseState  
def connect(target)  
owner.instance\_eval { @connection = target }  
next\_state StateOn.new(owner)  
true  
end  
…

Other optimizations are also possible, for example caching state  
instance if  
there are a lot state changes and they should be fast.

Kind regards

```
robert

```

---

<div class="post-metadata">

**Author:** ![Michael\_SentropieS\_S](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/6de8d8/32.png) [@Michael\_SentropieS\_S](https://www.ruby-forum.com/u/Michael_SentropieS_S)\
**Post date:** [January 9, 2006, 7:38pm UTC](https://www.ruby-forum.com/t/state-pattern/94626/3 "2006-01-09T19:38:29Z")

</div>

Hello Robert,

- Robert K. (removed\_email\_address@domain.invalid) wrote:

> > wrong path?)
> 
> Hm, I think you probably did not get there completely. For example the  
> toggle state metchod is typically implemented in the each state class  
> (every state knows the state that follows him under certain conditions,  
> like a finite state automata distributed across several classes). Also  
> inheriting TrueClass and FalseClass is generally not a good idea (instances  
> of FalseClass’s subclass won’t be treated as false).

Ok.

> […]  
> Other optimizations are also possible, for example caching state  
> instance  
> if there are a lot state changes and they should be fast.

Thanks much! I will take a deeper look.  
This was very helpful.

## So long

Michael ‘entropie’ Trommer; [http://ackro.org](http://ackro.org)

ruby -e “0.upto((a=‘njduspAhnbjm/dpn’).size-1){|x| a[x]-=1}; p  
‘mailto:’+a”

---

<div class="post-metadata">

**Author:** ![Michael\_SentropieS\_S](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/6de8d8/32.png) [@Michael\_SentropieS\_S](https://www.ruby-forum.com/u/Michael_SentropieS_S)\
**Post date:** [June 8, 2009, 9:23am UTC](https://www.ruby-forum.com/t/state-pattern/94626/4 "2009-06-08T09:23:37Z")

</div>

Michael ‘entropie’ Trommer wrote:

> Hello,
> 
> I found this State-pattern example on [1], and was interested to  
> find a way to make this more useable for standard classes (not just  
> servers as in the example)
> 
> I’am not so skilled in OO coding and ruby, so iam interested what you  
> all think.  
> (and is it another implementation of the state pattern or iam on the  
> wrong path?)

I just created this gem that you may find useful

> **[GitHub - dcadenas/state\_pattern: A Ruby state pattern implementation](https://github.com/dcadenas/state_pattern)**
>
> A Ruby state pattern implementation. Contribute to dcadenas/state\_pattern development by creating an account on GitHub.
