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…
[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=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.
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.