Wikipedia: Design Patterns -> Strategy pattern

Oto jaki kod proponuje wikipedia dla wzorca Strategy:

class Context
  def initialize(strategy)
    self.class.send :include, strategy
  end
end
 
module StrategyA
  def execute
     puts 'Doing the task the normal way'
  end
end
 
module StrategyB
  def execute
     puts 'Doing the task alternatively'
  end
end
 
module StrategyC
  def execute
     puts 'Doing the task even more alternatively'
  end
end
 
a = Context.new(StrategyA)
a.execute #=> Doing the task the normal way
 
b = Context.new(StrategyB)
b.execute #=> Doing the task alternatively
 
c = Context.new(StrategyC)
c.execute #=> Doing the task even more alternatively

Czy tylko ja uważam że jest to nie tylko brzydkie ale i niebezpieczne pod względem wielowątkowości? Chodzi o ten fragment:

self.class.send :include, strategy

zmiana strategii dokonuje się poprzez dołączenie modułu do klasy, co będzie skutkować zmianą strategii we wszystkich obiektach tej klasy, we wszystkich wątkach…

No ewidentnie kupy się to nie trzyma. Pierwszy przykład zupełnie nie ma sensu.

Ostro.

[quote=hubertlepicki]Czy tylko ja uważam że jest to nie tylko brzydkie ale i niebezpieczne pod względem wielowątkowości? Chodzi o ten fragment:

self.class.send :include, strategy

zmiana strategii dokonuje się poprzez dołączenie modułu do klasy, co będzie skutkować zmianą strategii we wszystkich obiektach tej klasy, we wszystkich wątkach…[/quote]
W cholerę niebezpieczne, ale nie ma to nic wspólnego z wielowątkowością:

a = Context.new(StrategyA) b = Context.new(StrategyB) c = Context.new(StrategyC) a.execute b.execute c.execute

Doing the task even more alternatively Doing the task even more alternatively Doing the task even more alternatively

[quote=radarek]Ostro.

[quote=hubertlepicki]Czy tylko ja uważam że jest to nie tylko brzydkie ale i niebezpieczne pod względem wielowątkowości? Chodzi o ten fragment:

self.class.send :include, strategy

zmiana strategii dokonuje się poprzez dołączenie modułu do klasy, co będzie skutkować zmianą strategii we wszystkich obiektach tej klasy, we wszystkich wątkach…[/quote]
W cholerę niebezpieczne, ale nie ma to nic wspólnego z wielowątkowością:

a = Context.new(StrategyA) b = Context.new(StrategyB) c = Context.new(StrategyC) a.execute b.execute c.execute

Doing the task even more alternatively Doing the task even more alternatively Doing the task even more alternatively
[/quote]
Ma, również. Prawdopodobne jest że jedną instancję klasy użyjesz podczas jednego requestu, nie zauważysz w takim wypadku co jest źle dopóki nie zacznie się pieprzyć przy wielu wątkach. Ale racja, jeśli stworzysz wiele instancji tej samej klasy w jednym wątku to będzie równie spieprzone.

taki konstruktor chyba powinien rozwiązać problem?

class Context def initialize(strategy) extend strategy end end

Dokładnie taki pattern jest wymieniony w książce Refactoring, Ruby edition, kiedy działanie obiektu ma być zależne od strategii ale niezmienne po zainicjalizowaniu obiektu.